Handling multiple Facebook user logins in an iOS app

Viewed 1569

I have an iOS application that can have multiple users and I want to integrate Facebook into it. I would like to cache each user's login credentials. The users will have an application login so each user will only be able to use there own Facebook creds. Facebook's documentation states that you can manage multiple user's session tokens by overriding the FBSessionTokenCachingStrategy object here:

https://developers.facebook.com/docs/ios/login-tutorial/

I am using the local caching method and I have it working where a user logs into my application and then if they have a related Facebook token I log them into there session. Otherwise I prompt them to enter there Facebook credentials using Facebook's API that redirects the user to the Facebook web login page.

[FBSession openActiveSessionWithReadPermissions:@[@"basic_info"]
                                   allowLoginUI:YES
                              completionHandler:
 ^(FBSession *session, FBSessionState state, NSError *error)
 {
     [self loginToFacebookEnd:session state:state error:error];
 }];

The above method works great for the FIRST USER. The second user that goes to login gets redirected to the Facebook web login page as expected, but the first user is now logged in through safari and the second user is now logged in with the first users credentials.

I want to be able to either not have the user stay logged in on safari, OR be able to use something like the embedded web dialog. According to the Facebook API docs however, the embedded dialog however doesn't seem to let me load the users token after the app restarts:

https://developers.facebook.com/docs/ios/login-tutorial/#control

"Embedded WebView Login Dialog Disadvantage: People have to fill in their login credentials every time they go through the login flow."

Also, calling the following method clears out my token cache when the token was saved from an Embedded WebView:

FBSession *session = [[FBSession alloc] initWithAppID:nil
                                          permissions:@[@"basic_info"]
                                      urlSchemeSuffix:nil
                                   tokenCacheStrategy:tokenCaching];

Does anyone know how to support more than one user logging into Facebook from an iOS app without the first user's credentials getting cached in Safari?

UPDATE 1

Ok, I know it is possible to handle multiple users using the Embedded WebView now, because one of the sample programs Facebook includes with the SDK (SwitchUserSample) does it. Something seems to be wrong with loading my FBSession, as a lot of the values are null, though I am calling exactly the same code as the example. Does anyone know what would cause a session to restore like this:

<FBSession: 0x16d9f3a0, state: FBSessionStateCreated, loginHandler: 0x0, appID: 658013034244859, urlSchemeSuffix: , tokenCachingStrategy:<FBSessionTokenCachingStrategy: 0x16d56190>, expirationDate: (null), refreshDate: (null), attemptedRefreshDate: 0001-12-30 00:00:00 +0000, permissions:(null)>

If I use any behavior other than FBSessionLoginBehaviorForcingWebView, then I get this as my deserialized token:

<FBSession: 0x155823d0, state: FBSessionStateOpen, loginHandler: 0x73364, appID: 658013034244859, urlSchemeSuffix: , tokenCachingStrategy:<FBSessionTokenCachingStrategy: 0x15577c90>, expirationDate: 2014-02-15 20:01:50 +0000, refreshDate: 2013-12-17 20:01:51 +0000, attemptedRefreshDate: 0001-12-30 00:00:00 +0000, permissions:(
    "user_birthday",
    "user_friends"
)>

UPDATE 2

I have identified that it is definitely something to do with how my token is getting cached. I have copied over the methods the Facebook example is using but I am still getting null values for my dates in the FBSession. Here are the caching methods I am calling:

+ (FBSessionTokenCachingStrategy*)createCachingStrategyForSlot:(int)slot {
    FBSessionTokenCachingStrategy *tokenCachingStrategy = [[FBSessionTokenCachingStrategy alloc]
                                                           initWithUserDefaultTokenInformationKeyName:[NSString stringWithFormat:@"SUUserTokenInfo%d", slot]];
    return tokenCachingStrategy;
}

+ (FBSession*)createSessionForSlot:(int)slot {
    FBSessionTokenCachingStrategy *tokenCachingStrategy = [self createCachingStrategyForSlot:slot];
    FBSession *session = [[FBSession alloc] initWithAppID:nil
                                              permissions:@[@"basic_info",@"user_birthday"]
                                          urlSchemeSuffix:nil
                                       tokenCacheStrategy:tokenCachingStrategy];
    return session;
}

And here is how I am calling it:

+ (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI
{
    BOOL openSessionResult = NO;    
    FBSession *session = [self createSessionForSlot:1];

    // If showing the login UI, or if a cached token is available, then open the session.
    if (allowLoginUI || session.state == FBSessionStateCreatedTokenLoaded)
    {
        // For debugging purposes log if cached token was found
        if (session.state == FBSessionStateCreatedTokenLoaded)
        {
            NSLog(@"Cached token found.");
        }

        // Set the active session
        [FBSession setActiveSession:session];

        // If the session state is not any of the two "open" states when the button is clicked
        if (FBSession.activeSession.state != FBSessionStateOpen && FBSession.activeSession.state != FBSessionStateOpenTokenExtended)
        {
            // Open the session.
            [session openWithBehavior:FBSessionLoginBehaviorForcingWebView
                    completionHandler:^(FBSession *session,
                                        FBSessionState state,
                                        NSError *error)
             {
                 [SocialInteraction loginToFacebookEnd:session state:state error:error];
             }];
        }

        // Return the result - will be set to open immediately from the session
        // open call if a cached token was previously found.
        openSessionResult = session.isOpen;
    }
    return openSessionResult;
}

The frustrating part is that if I change the login behavior from FBSessionLoginBehaviorForcingWebView to FBSessionLoginBehaviorWithFallbackToWebView, then the token loads correctly! But, this behavior won't work for my application. There must be some other setting I am missing that would let the embedded WebView cache its token.

1 Answers
Related