Fetch cached access token through FBSession using Facebook SDK - facebook

Is there a way to fetch cached access token through FBSession using Facebook SDK if the user is logged in native Facebook.
I am trying to implement autologin through Facebook in an app i.e.when a user is logged in native Facebook then the app should not ask for the login and user should get automatically logged in.
I have used FBSession and FBTokenCacheStrategy and the user is getting logged in automatically but I am not able to fetch the access token which I need to call some API. The following code I am using to get this done :
CacheToken = [[FBTokenCache alloc]init];
NSArray *permissions = [[NSArray alloc]initWithObjects:#"email,user_photos,user_videos,publish_stream,offline_access,user_checkins,friends_checkins", nil];
self.fbsession = [[FBSession alloc] initWithAppID:#"484473011575776"
permissions:permissions
urlSchemeSuffix:nil
tokenCacheStrategy:CacheToken];
(fbsession is the object of Facebook SDK class FBSession)
[FBSession setActiveSession:self.fbsession];
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
Thanks in advance.

To get the access token you should use this:
[FBSession activeSession] accessToken]
However, it seems like you want to check whether there is already a (cached) access token. To do this you can do this:
// See if we have a valid token for the current state.
if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) {
NSLog(#"The value access token is: %#", [[FBSession activeSession] accessToken]);
} else {
// No, display the login page.
}
Make sure also to do this in your app delegate or the access token will be nil:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [FBSession.activeSession handleOpenURL:url];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// We need to properly handle activation of the application with regards to Facebook Login
// (e.g., returning from iOS 6.0 Login Dialog or from fast app switching).
[FBSession.activeSession handleDidBecomeActive];
}
Hope this helps

Try following code..
if (FBSession.activeSession.isOpen)
{
NSString *token = [[[FBSession activeSession] accessTokenData] accessToken];
}
hope this will work out for you..

Related

Facebook login in iOS app for multiple users on one device

My app will be used by multiple users.
How can I integrate facebook in a way so that the safari doesn't save any user credentials & throw a login page each time some one tries to login.
I already used FBSessionLoginBehaviorForcingWebView to force a web view login within the app but the problem is, when the first user tries to login to fb via the view presented within the app, the control then goes to safari for authentication & it just saves the creds.
So when other user tries to log in, & enters his credentials in the app local UIWebView, the control again goes to safari, which already has previos creds stored & the new user just cannot authenticate.
So basically the first user is permanently logged in. Clearing the cookies for web view doesn't work. I cant clear them for safari.
Help
Thanks in advance.
This is what I have been doing
if([FBSession activeSession].isOpen)
{
[[FBSession activeSession] closeAndClearTokenInformation];//Also, clearing all the local cookies
}
else
{
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
delegate.session = [[FBSession alloc] init];
[FBSession setActiveSession:delegate.session];
[delegate.session openWithBehavior:FBSessionLoginBehaviorForcingWebView completionHandler:^(FBSession *session1, FBSessionState status, NSError *error) {
if (!error) {
[self openSession]; // your method
}
}];
}
- (void)sessionStateChanged:(FBSession *)session state:(FBSessionState) state error:(NSError *)error{
switch (state) {
case FBSessionStateOpen:
{
[FBRequestConnection startForPostStatusUpdate:#"Some message"completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
//logout again
NSLog(#"startForPostStatusUpdate SUCESS");
}
else {
//logout again
NSLog(#"startForPostStatusUpdate FAIL");
}
}];
}
break;
case FBSessionStateClosed:
{
NSLog(#"FBSessionStateClosed");
}
break;
case FBSessionStateClosedLoginFailed:
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
if (error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error" message:error.localizedDescription delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}
}
Also, modified the app delegate with your methods.
Found a solution. Basically, calling the following:
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];
Only clears the local FB session information but not the Safari cookies. So, after I log in the user, I clear the Safari cookies:
NSHTTPCookie *cookie;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [storage cookies]) {
[storage deleteCookie:cookie];
}
[[NSUserDefaults standardUserDefaults] synchronize];
It isn't very elegant, but it works. Now, when the next user tries to log in, it forces them to enter their credentials.
You just need to use this method after you want to close the FB Session.
[FBSession.activeSession closeAndClearTokenInformation];
This will clear the Facebook Token, and whenever button will be pressed for Facebook share, it will ask for new token credential and it will show Facebook login view again.
Use following code in AppDelegate
// This method will handle facebook session.
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
// Facebook SDK * login flow *
// Attempt to handle URLs to complete any auth (e.g., SSO) flow.
return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication fallbackHandler:^(FBAppCall *call) {
// Facebook SDK * App Linking *
// For simplicity, this sample will ignore the link if the session is already
// open but a more advanced app could support features like user switching.
if (call.accessTokenData) {
if ([FBSession activeSession].isOpen) {
NSLog(#"INFO: Ignoring app link because current session is open.");
}
else {
[self handleAppLink:call.accessTokenData];
}
}
}];
}
// Helper method to wrap logic for handling app links.
- (void)handleAppLink:(FBAccessTokenData *)appLinkToken {
// Initialize a new blank session instance...
FBSession *appLinkSession = [[FBSession alloc] initWithAppID:nil
permissions:nil
defaultAudience:FBSessionDefaultAudienceNone
urlSchemeSuffix:nil
tokenCacheStrategy:[FBSessionTokenCachingStrategy nullCacheInstance] ];
[FBSession setActiveSession:appLinkSession];
// ... and open it from the App Link's Token.
[appLinkSession openFromAccessTokenData:appLinkToken
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
// Forward any errors to the FBLoginView delegate.
if (error) {
//TODO: Show error here
}
}];
}
Add following code where you are opening session for Facebook
/***********************************************************************
This method opens browser or App Url to FB authentication and change FB
session state
************************************************************************/
- (void)openSession
{
NSArray *permisssions = [[NSArray alloc] initWithObjects:#"email",#"user_photos",nil];
[FBSession openActiveSessionWithReadPermissions:permisssions
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
/***********************************************************************
This method will be called whenever FB Session state changed
It also shows an error message if any error occurs
************************************************************************/
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen: {
NSLog(#"FBSession Open State");
//Enter your code what you want to perform when session is open
}
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
// Once the user has logged in, we want them to
// be looking at the root view.
NSLog(#"FBSession State Closed");
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];
break;
default:
break;
}
if (error) {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:#"Error"
message:error.localizedDescription
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
}
}
Now when ever user tap on Facebook Share button check that session exists or not. If not then call openSession method. It will open facebook login view.
There is a sample in the Facebook Github repository, showing how to switch between multiple users.
It looks like it requires use of the custom login flow.

how to check if already logged in Facebook in ios?

I am using "Graph Api" For Facebook login with in my app. I successfully logIn and logged out with this code
facebook = [[Facebook alloc] initWithAppId:kAppId andDelegate:self.viewController];
and i using below code for already facebook logged in
if (![facebook isSessionValid]) {
[facebook authorize:permissions ];
}
My problem is i install Facebook App, and i logged in via Facebook App. then i run my app, it ask again login Facebook. how i solve this issue. it should take as a default FB app login credentials. i saw many app using this feature. anyone know the solution
1. In your AppDelegate.m file
define NSString *const FBSessionStateChangedNotification =
#"com.example:FBSessionStateChangedNotification";
replace com.example with your bundle identifier name
2.- In method
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[FBSession setActiveSession:[FBSession new]];
if ([FBSession activeSession].state == FBSessionStateCreatedTokenLoaded)
{
// means u are already logged in
//do ur code
[self openSessionWithAllowLoginUI:NO];
}
else
{ //do ur code
[self openSessionWithAllowLoginUI:YES];
}
}
3. whenenever and wherever this method is called after end of switch case write
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
[[NSNotificationCenter defaultCenter]
postNotificationName:FBSessionStateChangedNotification
object:session];
}
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI
{
return [FBSession openActiveSessionWithReadPermissions:#"email"
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session, FBSessionState state, NSError *error)
{
[self sessionStateChanged:session state:state error:error];
}];
}
Sorry in your appDelegate.h file it should be
extern NSString *const FBSessionStateChangedNotification;

iOS native Facebook Login fails for Mobile Safari authentication

I have a native iOS app with Facebook Login integrated. The login flow works when the native Facebook app is installed.
However, when I delete the app, the FB login fallback on FB Mobile Safari webapp. The app switching works fine, but when controls come back to my app, the state of the session is declared FBSessionStateClosedLoginFailed.
I am using Facebook SDK v3.5.2 as of June 6th, 2013
Using iPad1 iOS5.1.1
/*
* Opens a Facebook session and optionally shows the login UX.
*/
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"email",
#"publish_actions",
nil];
BOOL result = NO;
FBSession *session =
[[FBSession alloc] initWithAppID:nil
permissions:permissions
urlSchemeSuffix:#"<MySchemeSuffix>"
tokenCacheStrategy:nil];
if (allowLoginUI ||
(session.state == FBSessionStateCreatedTokenLoaded)) {
[FBSession setActiveSession:session];
[session openWithBehavior:FBSessionLoginBehaviorWithFallbackToWebView
completionHandler:
^(FBSession *session, FBSessionState state, NSError *error)
{
[self sessionStateChanged:session state:state error:error];
}];
result = session.isOpen;
}
return result;
}
/*
* If we have a valid session at the time of openURL call, we handle
* Facebook transitions by passing the url argument to handleOpenURL
*/
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// attempt to extract a token from the url
//return [FBSession.activeSession handleOpenURL:url];
BOOL urlWasHandled = [FBAppCall handleOpenURL:url
sourceApplication:sourceApplication
fallbackHandler:^(FBAppCall *call) {
// handle deep links and responses for Login or Share Dialog here
}];
return urlWasHandled;
}
/*
* Callback for session changes.
*/
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen:
if (!error) {
if (FBSession.activeSession.isOpen) {
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
//Application specific code goes here.
}
}];
}
// We have a valid session
NSLog(#"User session found");
}
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
}
I happened to fix the issue.
The bug was, I was requesting read and write permissions in the same call.
Taking out the "publish_actions" from permissions solved the issue.
I tested Facebook Login in iOS6+ through native FB login, native FB app, and webapp.
Also tested on iOS5.1.1 through native FB app, and webapp.

Facebook authentication doesnot auto closes

I am trying to integrating Facebook-Connect SDK to a cocos2d-x game on iOS platform.
I am using the api,
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:TRUE
completionHandler:^(FBSession *session, FBSessionState state, NSError *error)
{
if(state == FBSessionStateOpen)
NSLog(#"Success");
}
Dialog box doesn't close on pressing okay, however the completionHandler executes successfully with FBSessionStateOpenstate.
I see you tagged this question iOS 6 so I'm assuming you are developing this game for iOS 6 devices which you'll be able to use iOS 6 integration with Facebook.
I explained how i did it once (https://stackoverflow.com/a/14151853/1449151) but I put it here anyway. If you like to use iOS 6 Facebook integration you could follow these steps to make sure you did all of them right. (for instance I see your permission is nil, see how i did it below). Hope it helps:
OK here is how I do this integration with iOS 6 and get what I want from Facebook:
In AppDelegate I do this:
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
return [FBSession.activeSession handleOpenURL:url];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[FBSession.activeSession handleDidBecomeActive];
}
- (void)applicationWillTerminate:(UIApplication *)application
{
[FBSession.activeSession close];
}
and in my ViewController where I want to retrieve information about myself or my friends I do this (NOTE: this is a test, so it is a lot of permissions!):
NSArray *permissions =
[NSArray arrayWithObjects:#"email", #"user_location",
#"user_birthday",
#"user_likes", #"user_interests",#"friends_interests",#"friends_birthday",#"friends_location",#"friends_hometown",#"friends_photos",#"friends_status",
#"friends_about_me", #"friends_birthday", #"friends_hometown", #"friends_interests", #"friends_likes", #"friends_location", nil];
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
/* handle success + failure in block */
if (status) {
NSLog(#"Facebook Read Permission is successful!");
[self presentPostOptions];
// [self presentPostOptions];
}
}];
Then in "presentPostOptions" I do this (in this example I try to retrieve something from my friend):
- (void)presentPostOptions
{
[[FBRequest requestForMyFriends] startWithCompletionHandler:^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error)
{
if (!error) {
NSArray *data = [user objectForKey:#"data"];
NSLog(#"%d", [data count]);
for (FBGraphObject<FBGraphUser> *friend in data) {
NSLog(#"%#", [friend first_name]);
NSLog(#"%#", [friend last_name]);
NSLog(#"%#", [friend id]);
//make sure you have FBProfilePictureView outlet in your view
//otherwise skip the profile picture!
self.fbProfilePic.profileID = #"you'r friend's profile.id";
}
}
else
{
NSLog(#"error");
// [self didFailWithError:error];
}
}];
I don't know what else you want to do because in your question you just tried to make a connection but this way you can do what ever you want while you are integrated in iOS 6.
One more thing, make sure about your App Settings over Facebook and the configs over there like enable your app for iOS and the ID for iPhone/iPad. Also the FacebookAppID in your plist.
Let me know if it works out for you,
EDIT: My Facebook SDK is 3.1.1 btw.

ios6 facebook integration login always FBSessionStateClosedLoginFailed never opens

this question is very similar to Facebook SDK for iOS , on iOS 4.0 device, but as I cannot make comments there, I open a new question. I think the questions are not the same:
When trying to update the facebook integration of my app to facebook 3.1 I am not getting the facebook session to open the sessionStateChanged Callback always ends up in FBSessionStateClosedLoginFailed. in my setup I have the callback in my appdelegate
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
// attempt to extract a token from the url
// return [self.session handleOpenURL:url];
return [FBSession.activeSession handleOpenURL:url];
}
but it is never called! shouldn't it get called? I followed the facebook documentation and call
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
NSArray *permissions = [NSArray arrayWithObjects:#"publish_actions", nil];
return [FBSession openActiveSessionWithPublishPermissions:permissions
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
[self sessionStateChanged:session
state:state
error:error];
}];
}
I also tried
openActiveSessionWithReadPermissions with nil for the permissions as in the facebook tutorial example with the intention to reauthorize for the publish_actions permission later. same result: FBSessionStateClosedLoginFailed again.
I even tried calling
ACAccountStore *accountStore;
ACAccountType *accountTypeFB;
if ((accountStore = [[ACAccountStore alloc] init]) &&
(accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook] ) ){
NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB];
id account;
if (fbAccounts && [fbAccounts count] > 0 &&
(account = [fbAccounts objectAtIndex:0])){
[accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) {
//we don't actually need to inspect renewResult or error.
if (error){
}
}];
}
}
before trying to open the session, but I never get it open on my ios6 device (iphone 4s). in the app I am asked for the permission, but then nothing goes on because the session is always having the state FBSessionStateClosedLoginFailed! my callback for the session state is
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
switch (state) {
case FBSessionStateOpen:
if (!error) {
// We have a valid session
NSLog(#"User session found");
}
break;
case FBSessionStateClosed:
NSLog(#"FBSessionStateClosed");
case FBSessionStateClosedLoginFailed:
NSLog(#"FBSessionStateClosedLoginFailed");
[FBSession.activeSession closeAndClearTokenInformation];
break;
default:
break;
}
[[NSNotificationCenter defaultCenter]
postNotificationName:FBSessionStateChangedNotification
object:session];
if (error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"facebook Hinweis"
message:#"facebook Login nicht möglich, bitte versuchen Sie es erneut."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
NSLog(#"Facebook session error: %#", error.localizedDescription);
}
}
with the facebook 3.0 on ios 5 I never had an issue so my facebook app is set up correctly. I would really appreciate any help wchich enables me to just open the facebook session, did not think to run into these problems with facebook 3.1 and the docs are not helping me at this point, thx
I had the same problem, and it was because I forgot to implement
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
return [FBSession.activeSession handleOpenURL:url];
}
in my AppDelegate
While JohnG's answer is correct, that particular delegate method has now been deprecated. The correct delegate method to use is this:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [FBSession.activeSession handleOpenURL:url];
}
Placing that in my application delegate solved the issue for me. Without this, the iOS 6.0 native login would work but the Facebook app login would fail.
I had the same problem. If the user hadn't a Facebook account configured in the System Preferences the Facebook login dialog appeared and everything worked fine. But if the user had an account configured in the device I was always having a FBSessionStateClosedLoginFailed error.
It has nothing to do with handleOpenURL:url because in the "native login flow" for iOS 6 or greater there is no fast-app-change. So your app never goes to background and the URL redirection is not needed.
The problem was solved configuring the Facebook app. You need to enable the "Native iOS login" section and put the bundle ID of your app. If your app is not already in the Apple Store I'm afraid you need to set the sandbox mode to ON. Once your app is published in the Apple Store I think you need to put the sandbox mode to OFF and set the Apple Store ID in the Facebook configuration.
Even i can't comment so writing it as answer .
I am not sure , let me analyze potential reasons
1) you said: "but it is never called! shouldn't it get called?" -- for
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
to get called , in the info.plist file , url scheme should be set properly i.e go to URL types-->Item0-->URL Schemes--->Item 0 the value here should be fbAPPID i.e fb append with your actual facebookappID [FacebookAppID could also be present in the info.plist or hard coded in code].
2)You said:
"sessionStateChanged Callback always ends up in FBSessionStateClosedLoginFailed"
In the sessionStateChanged switch method check the state of session and if it created or createdTokenLoaded then try to open the session.
Note:[FBSession openActiveSessionWithPublishPermissions ....] which is a static method will create a new session and is set to FBSession.activeSession where as openWithCompletionHandler is an instance method which can work only if the session is already created .
case FBSessionStateCreated:
case FBSessionStateCreatedTokenLoaded:{
[session openWithCompletionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
//handle the updating of views according to the sate of session
}];
break;
I agree with JohnG, with the additional caveat of:
Note that if you have multiple cases inside of handleOpenURL:, you can filter for:
if ([sourceApplication isEqualToString:#"com.facebook.facebook"] ||
[sourceApplication isEqualToString:#"com.facebook.Facebook"]){
//Do Stuff
}
It's weird, but I was able to replicate on multiple devices the sourceApplication coming back as "Facebook" and "facebook".
On FB SDK 3.5, You can kill the token with this:
[[FBSessionTokenCachingStrategy defaultInstance] clearToken];