How to Log Out of Facebook in iOS - facebook

I know how to log in
[FBSession openActiveSessionWithReadPermissions:readPermissions allowLoginUI:YES completionHandler:
^(FBSession *session,FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];//This is done on main thread already
}];
The thing is what to do at logout, say when user press the logout button?
Currently I simply do
[FBSession.activeSession closeAndClearTokenInformation];
[[NSNotificationCenter defaultCenter] postNotificationName:FACEBOOKSESSIONCHANGED object:self];
However, I do not think that's true. [FBSession.activeSession closeAndClearTokenInformation]; should be called at [self sessionStateChanged:session state:state error:error]; AFTER logging out.
So what should I do to logout?
I check scrumptuous sample from facebook, I couldn't find their mechanism to logout. It seems that they use specialized facebook viewController that has a delegate. But none of the delegate is called.

Logging out mechanism , they just invalidate the access token by releasing it and setting it to nil. But if your login is using safari then still the cookies would exists. So next time if user open safari and try to access Facebook it would say that it is already authorized.
To delete the cookies I use the following method
- (void)fbDidLogout
{
NSLog(#"Logged out of facebook");
NSHTTPCookie *cookie;
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [storage cookies])
{
NSString* domainName = [cookie domain];
NSRange domainRange = [domainName rangeOfString:#"facebook"];
if(domainRange.length > 0)
{
[storage deleteCookie:cookie];
}
}
}
To be more sure you can also call as some bugs are there which return open session even after calling closeAndClearTokenInformation. https://developers.facebook.com/bugs/497294866962479?browse=search_507cb8ebc4f025673237228
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];
Other option is to use the following condition while checking for active session .
if (FBSession.activeSession.isOpen)
//logged in
else
//not logged in
Because FBSession.activeSession.state was returning FBSessionStateOpen, not FBSessionStateCreatedTokenLoaded.

not sure if anyone is still getting bitten by this, but with the latest version of the Facebook SDK, i cannot get an iPad to be forced to log in after logging out. There is still some sort of weirdness here - the 'clear cookies' code is being jumped over - is there a different way to clear cookies in the iPad?
Jerry

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.

The operation couldn't be completed.(com.facebook.sdk error 2.) error iOS 6 [duplicate]

I'm using die Facebook SDK 3.1.1 to implement FB Connect in my iOS application. This works fine in the simple case with either the new FB integration (logged in on iOS) or falling back to the normal authorization via web view (I do not have the native Facebook application installed in both cases).
The problem occurs when I switch the account on iOS level. Logging out and logging in with a different FB user account.
To log in/authorize I perform:
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:allowLoginUI
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
If then get a FBSessionStateClosedLoginFailed every time even though I perform a closeAndClearTokenInformation when that state is reached:
- (void)sessionStateChanged:(FBSession *)session
state:(FBSessionState) state
error:(NSError *)error
{
NSLog(#"Session State Changed: %u", [[FBSession activeSession] state]);
switch (state) {
case FBSessionStateOpen:
break;
case FBSessionStateClosed:
case FBSessionStateClosedLoginFailed:
NSLog(#"FBSessionStateClosedLoginFailed ERROR: %#", [error description]);
[[FBSession activeSession] closeAndClearTokenInformation];
break;
default:
break;
}
However, I receive the same state on every retry. My log says the following:
FBSDKLog: FBSession **INVALID** transition from FBSessionStateCreated to FBSessionStateClosed
FBSDKLog: FBSession transition from FBSessionStateCreated to FBSessionStateCreatedOpening
FBSDKLog: FBSession transition from FBSessionStateCreatedOpening to FBSessionStateClosedLoginFailed Session State Changed: 257
FBSessionStateClosedLoginFailed TOKEN: (null)
FBSessionStateClosedLoginFailed ERROR: Error Domain=com.facebook.sdk Code=2 "The operation couldn’t be completed. (com.facebook.sdk error 2.)" UserInfo=0xb24cc20 {com.facebook.sdk:ErrorLoginFailedReason=com.facebook.sdk:ErrorLoginFailedReason}
Can anyone reproduce this or has any idea where the problem might lie?
Another answer gives a way to manually resync the device with the server. I defined a method called fbRsync to call this code. Make sure to #import <Accounts/Accounts.h> in your implementation file and then define this method:
-(void)fbResync
{
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){
}
}];
}
}
I then call fbResync if openActiveSessionWithReadPermissions yields an error:
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
if(error)
{
NSLog(#"Session error");
[self fbResync];
[NSThread sleepForTimeInterval:0.5]; //half a second
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
}
else
[self sessionStateChanged:session state:state error:error];
}];
The half a second delay is likely unnecessary, but it currently gives me piece of mind.
This seems to solve the problem for me. I can now switch between Facebook accounts and am able to log in. Yay!
I had the same problem. Check that your FB App is enabled in Settings -> Facebook.
Mine was disabled (even though I don't remember disabling it) and once I enabled it, it was fixed.
In my test process, I've added and removed my FB App several times from my FB Account, which is linked with my iPhone. It may explain why, magically, my app was disabled.
In ios 6 with fb sdk 3.1.1. Please pass permissions param as "nil or email" in "[FBSessio openActiveSessionWithReadPermissions..." method. Here my code it was works great.
#define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 )
-(void)showFBLogin
{
[FBSession.activeSession closeAndClearTokenInformation];
NSArray *permissions = [NSArray arrayWithObjects:#"email, publish_actions, publish_stream", nil];
#ifdef IOS_NEWER_OR_EQUAL_TO_6
permissions = nil; or NSArray *permissions = [NSArray arrayWithObjects:#"email",nil];
#endif
NSLog(#"\npermissions = %#", permissions);
[FBSession openActiveSessionWithReadPermissions:permissions
allowLoginUI:YES
completionHandler:
^(FBSession *session,
FBSessionState state, NSError *error) {
NSLog(#"\nfb sdk error = %#", error);
switch (state) {
case FBSessionStateOpen:
[[FBRequest requestForMe] startWithCompletionHandler:
^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
if (!error) {
//success
}
}];
break;
case FBSessionStateClosed:
//need to handle
break;
case FBSessionStateClosedLoginFailed:
//need to handle
break;
default:
break;
}
}];
}
I have the same problem on 3.1.3 FB SDK with iOS7.1. And I find a solution here. Hope it help!!
I have tried all answers here.
#loganathan nil permissions, #ill_always_be_a_warriors fbResync.
All of those don't work for me.
But I found it will works well when I launch the same code in iPhone 7.1 simulator
(without SSO"Single Sign On")
The same code works well on old version iOS FB SDK(not sure which version, but not 3.13)
(but no SSO will show when try to login)
So, I try to re-write a sample problem. I found several different here.
1. https://developers.facebook.com/docs/ios/getting-started Add new FacebookDisplayName
2. I modify my BundleID for iTune connect but I am not update it back to Faceboook App Dev
After modify those setting, it works on my iOS app with SSO feature.
Hope it help!!
Did you Try the RenewSystemCredential Methods? Take a look at this post:
Facebook iOS SDK extendAccessToken not Working - fbDidExtendToken not being called
I got the same error. But i used #ill_always_be_a_warriors method: -(void)fbResync but not work for me.
I finally found it's my permissions issue, i removed offline_access permission, it works, hope it helps some one.

Close Facebook session in Facebook-Ios-Sdk

How do I close aCtive Session Of the Facebook-iOS-Sdk each time when i start my app either after killing app it gives me the previous login session details. When I click on the facebook Button .I have used everything [appDelegate.session closeAndClearTokenInformation];
[FBSession.activeSession close]; [FBSession.activeSession closeAndClearTokenInformation] ..but active session still not been close..how do i close the Previous session data on clicking.
I use the below code to clear but whenever I click on the facebook button to start new session..it gives me back the previous credentials.
- (IBAction)buttonClickHandler:(id)sender {
appDelegate = [[UIApplication sharedApplication]delegate];
// this button's job is to flip-flop the session from open to closed
if (appDelegate.session.isOpen) {
[appDelegate.session closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession.activeSession closeAndClearTokenInformation];
FBSession.activeSession=nil;
} else {
if (appDelegate.session.state != FBSessionStateCreated) {
// Create a new, logged out session.
appDelegate.session = [[FBSession alloc] init];
}
// if the session isn't open, let's open it now and present the login UX to the user
[FBSession.activeSession closeAndClearTokenInformation];
FBSession.activeSession=nil;
[FBSession.activeSession openWithBehavior:FBSessionLoginBehaviorForcingWebView
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error) {
// and here we make sure to update our UX according to the new session state
NSLog(#" state=%d",state);
[FBRequestConnection
startForMeWithCompletionHandler:^(FBRequestConnection *connection,
id<FBGraphUser> user,
NSError *error) {
userInfo = #"";
// Example: typed access (name)
// - no special permissions required
userInfo = user.username;
NSLog(#"string %#", userInfo);
[self checkfacebook];
}];
}]; }
}
and in ViewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
if (!appDelegate.session.isOpen) {
// create a fresh session object
appDelegate.session = [[FBSession alloc] init];
if (appDelegate.session.state == FBSessionStateCreatedTokenLoaded) {
// even though we had a cached token, we need to login to make the session usable
[FBSession.activeSession close];
FBSession.activeSession=nil;
}
}
NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray* facebookCookies = [cookies cookiesForURL:[NSURL URLWithString:#"http://login.facebook.com"]];
for (NSHTTPCookie* cookie in facebookCookies) {
[cookies deleteCookie:cookie];
}
}
hi Christien may be bellow two link its help's you please refur this two link of developers.facebook
http://developers.facebook.com/docs/reference/ios/3.0/class/FBSession/
http://developers.facebook.com/docs/reference/ios/3.0/class/FBSession/#close
[FBSession.activeSession closeAndClearTokenInformation];
[FBSession.activeSession close];
[FBSession setActiveSession:nil];
you can also check this two question related your issue :-
Facebook graph api log out not working
Facebook iOS SDK 3.1.1 "closeAndClearTokenInformation" method no working
hope its helps you
After calling
[FBSession.activeSession closeAndClearTokenInformation];
use following to clear cookies. It worked for me!
NSHTTPCookieStorage* cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie* cookie in
[[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
[cookies deleteCookie:cookie];
}
Nitin's Gohel answer, Swift version:
FBSession.activeSession().closeAndClearTokenInformation()
FBSession.activeSession().close()
FBSession.setActiveSession(FBSession())
you can use
FBSession.setActiveSession(nil)
But the function ask for an unwrapped object, so "nil" seems not a good parameter to be pass

Fetch cached access token through FBSession using Facebook SDK

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..

FBSession often fails to be at FBSessionStateCreatedTokenLoaded when returning to foreground

I am using Facebook iOS SDK3.0 (client is not ready to move to 3.1 yet), and have been having trouble to get FBSession to be at the FBSessionStateCreatedTokenLoaded when the app returns to the foreground after a longer period of time (close to a day); I don't have issue if I just send the app to background and come back to the foreground after a minute or two
my code is as follow, please let me know if I should provide further information; I have this issues across devices (4, 4S, 5) and iOS version (4.3, 5.0, 5.1, 6.0)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
if (![self openSessionWithAllowLoginUI:NO]) {
// still allow loading the public feed even though user is not logged in (the view controller will have a login button overlay)
[[self pictureFeedVC] loadFeed];
}
...
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
DEBUGLog(#"didBecomeActive");
DEBUGLog(#"FBSession is Open? %#",FBSession.activeSession.isOpen ? #"YES" : #"NO");
if (FBSession.activeSession.state == FBSessionStateCreatedOpening) {
//Dismiss login view controller
if ([self.tabBarController modalViewController]) {
[self.tabBarController dismissModalViewControllerAnimated:NO];
}
[FBSession.activeSession close];
}
}
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
BOOL result = NO;
[FBSettings setLoggingBehavior:[NSSet setWithObjects:FBLoggingBehaviorSessionStateTransitions,nil]];
NSArray *permissions = [NSArray arrayWithObjects:#"publish_actions", #"email", nil];
FBSession *session = [[FBSession alloc] initWithAppID:nil permissions:permissions urlSchemeSuffix:FB_URL_SCHEME_SUFFIX tokenCacheStrategy:nil];
if (allowLoginUI || (session.state == FBSessionStateCreatedTokenLoaded)) {
[FBSession setActiveSession:session];
[session openWithCompletionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
[self sessionStateChanged:session state:state error:error];
}];
result = session.isOpen;
}
return result;
}
- (void)sessionStateChanged:(FBSession *)session state:(FBSessionState)state error:(NSError *)error
{
DEBUGLog(#"changed FB state");
switch (state) {
case FBSessionStateOpen:
if (!error) {
DEBUGLog(#"FBSessionStateOpen");
[[self pictureFeedVC] loadFeed];
}
break;
case FBSessionStateClosed:
DEBUGLog(#"FBSessionStateClosed");
case FBSessionStateClosedLoginFailed:
DEBUGLog(#"FBSessionStateClosedLoginFailed");
[session closeAndClearTokenInformation];
[self.tabBarController showFBLoginView];
break;
default:
break;
}
}
I am having problem where after extended period in the background, the DEBUGLog(#"FBSession is Open? %#",FBSession.activeSession.isOpen ? #"YES" : #"NO"); in applicationDidBecomeActive: will print a NO
more info: this app relies on Facebook login entirely, it uses facebook user ID to identify users, therefore for lots of actions I need to pass the Facebook access token so that the server can get the facebook user ID even though a lot of times those actions does not require api calls to facebook (besides getting the user ID from the access token of course). My other question is whether I need to actively do something to refresh the token or do something keep the FBSession open (if so, how?), would that be the reason why the FBSession.activeSession might not be in an open state when I return to foreground?
Thanks much in advance!