Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to refresh an oauth token when using the Facebook iPhone SDK

I'm using the Facebook SDK for iOS in my app: http://github.com/facebook/facebook-ios-sdk

The oAuth token expires after about 2 hours. How can I "refresh" the oAuth token without having to call the [Facebook authorize...] method again - which shows an empty Facebook dialog briefly if the user had previously logged in? What I want to avoid is requiring the user to re-login to FB each time they use the app - say, day to day.

I am already saving / restoring oAuth tokens when the app exits / starts. And I can check to see if the token is valid using [Facebook isSessionValid], or by checking the expire time on the token. But what to do if the token has expired? I've read that it is possible to "refresh" the token, but I don't understand how this is done.

I don't want to request "offline_access" permission, which would give me a "forever" token.

Help!?

like image 532
TomSwift Avatar asked Aug 31 '10 15:08

TomSwift


2 Answers

Facebook's implementation of OAuth doesn't support token refresh.

You have 2 types of access_tokens in Facebook. Short term token, which is given by default and a long term token which is given if you request offline_access. If refresh token were supported, it was the same as giving a offline_access token for all apps.

As long as the user has an active facebook session on your web control, you can request a new access_token just by accessing https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=http://www.facebook.com/connect/login_success.html&response_type=token or probably some iOS SDK command that does the same (never worked with it so I can't tell). This kind of request will not ask the user to login again, but will use the previous session that was created during the first login.

like image 124
fudge Avatar answered Nov 13 '22 15:11

fudge


Since none of these answers actually addressed the question I am going to detail how I have implemented OAuth token refresh using The Facebook SDK.

The SDK will automatically refresh your tokens when you make requests however, in my scenario we send the tokens to our servers and we need to use the latest token. So when our server indicates that we need new tokens this is what we do:

Note You can either pass the AppID into the FBSession or you can add the FacebookAppID key to your App's plist (this is what we do).

- (void)renewFacebookCredentials {
    if (FBSession.activeSession.state == FBSessionStateOpen ||
        FBSession.activeSession.state == FBSessionStateOpenTokenExtended) {
        [self sessionStateChanged:[FBSession activeSession] state:[FBSession activeSession].state error:nil];
    } else {
        // Open a session showing the user the login UI
        // You must ALWAYS ask for public_profile permissions when opening a session
        [FBSession openActiveSessionWithReadPermissions:@[@"public_profile",@"email"]
                                           allowLoginUI:NO
                                      completionHandler:^(FBSession *session, FBSessionState state, NSError *error) {
                                          //this block will run throughout the lifetime of the app.
                                          [self sessionStateChanged:session state:state error:error];
                                      }];
    }
}

The you can use the sessionStateChanged: method that Facebook include in their documentation but a simplified handler looks like this:

- (void)sessionStateChanged:(FBSession *)session state:(FBSessionState) state error:(NSError *)error {
    // If the session was opened successfully
    NSString *accessToken;
    if (!error && state == FBSessionStateOpen && [[session accessTokenData] accessToken]){
        // Show the user the logged-in UI

        //@see http://stackoverflow.com/questions/20623728/getting-username-and-profile-picture-from-facebook-ios-7
        accessToken = [[session accessTokenData] accessToken];
       //Now we have an access token, can send this to the server...
    } else {
       //No access token, show a dialog or something
    }

   //either call a delegate or a completion handler here with the accessToken
}

Be aware that some of the FBSession API calls check for thread affinity so I found that I had to wrap all my FBSession calls inside a dispatch_async(dispatch_get_main_queue(), ^{...

like image 26
Daniel Galasko Avatar answered Nov 13 '22 15:11

Daniel Galasko