Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if accesstoken is expired Facebook SDK 4.7 ios

I am using facebook sdk 4.7 and I need to check if accesstoken is expired.

FBSDKAccessToken *access_token = [FBSDKAccessToken currentAccessToken];
    if (access_token != nil) {
        //user is not logged in

        //How to Check if access token is expired?
        if ([access_token isExpired]) {
            //access token is expired ......
            //
        }
    }

And if I success with that I have to log the user again.

The SDK gives an expiration_date.how can that help? The device may have wrong date.

like image 571
mmrayyan Avatar asked Mar 15 '23 08:03

mmrayyan


1 Answers

Assuming user has been logged in with Facebook before and has [FBSDKAccessToken currentAccessToken] != nil(I am not going into details here, because login via FB is another story).

In my app, I do the following to make sure the FB access token is always valid and synced with my app server.

To keep it simple, all the code below is in AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // ...

    /** 
        Add observer BEFORE FBSDKApplicationDelegate's 
        application:didFinishLaunchingWithOptions: returns

        FB SDK sends the notification at the time it 
        reads token from internal cache, so our app has a chance 
        to be notified about this.
    */
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(fbAccessTokenDidChange:) 
                                                 name:FBSDKAccessTokenDidChangeNotification 
                                               object:nil];

    return [[FBSDKApplicationDelegate sharedInstance] application: application didFinishLaunchingWithOptions: launchOptions];
}

- (void)fbAccessTokenDidChange:(NSNotification*)notification
{
    if ([notification.name isEqualToString:FBSDKAccessTokenDidChangeNotification]) {

        FBSDKAccessToken* oldToken = [notification.userInfo valueForKey: FBSDKAccessTokenChangeOldKey];
        FBSDKAccessToken* newToken = [notification.userInfo valueForKey: FBSDKAccessTokenChangeNewKey];

        NSLog(@"FB access token did change notification\nOLD token:\t%@\nNEW token:\t%@", oldToken.tokenString, newToken.tokenString);

        // initial token setup when user is logged in
        if (newToken != nil && oldToken == nil) {

            // check the expiration data

            // IF token is not expired
            // THEN log user out
            // ELSE sync token with the server

            NSDate *nowDate = [NSDate date];
            NSDate *fbExpirationDate = [FBSDKAccessToken currentAccessToken].expirationDate;
            if ([fbExpirationDate compare:nowDate] != NSOrderedDescending) {
                NSLog(@"FB token: expired");

                // this means user launched the app after 60+ days of inactivity,
                // in this case FB SDK cannot refresh token automatically, so 
                // you have to walk user thought the initial log in with FB flow

                // for the sake of simplicity, just logging user out from Facebook here
                [self logoutFacebook];
            }
            else {
                [self syncFacebookAccessTokenWithServer];
            }
        }

        // change in token string
        else if (newToken != nil && oldToken != nil
            && ![oldToken.tokenString isEqualToString:newToken.tokenString]) {
            NSLog(@"FB access token string did change");

            [self syncFacebookAccessTokenWithServer];
        }

        // moving from "logged in" state to "logged out" state
        // e.g. user canceled FB re-login flow
        else if (newToken == nil && oldToken != nil) {
            NSLog(@"FB access token string did become nil");
        }

        // upon token did change event we attempting to get FB profile info via current token (if exists)
        // this gives us an ability to check via OG API that the current token is valid
        [self requestFacebookUserInfo];
    }
}

- (void)logoutFacebook
{
    if ([FBSDKAccessToken currentAccessToken]) {
        [[FBSDKLoginManager new] logOut];
    }
}

- (void)syncFacebookAccessTokenWithServer
{
    if (![FBSDKAccessToken currentAccessToken]) {
        // returns if empty token
        return;
    }

    // BOOL isAlreadySynced = ...
    // if (!isAlreadySynced) {
        // call an API to sync FB access token with the server
    // }
}

- (void)requestFacebookUserInfo
{
    if (![FBSDKAccessToken currentAccessToken]) {
        // returns if empty token
        return;
    }

    NSDictionary* parameters = @{@"fields": @"id, name"};
    FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me"
                                                                   parameters:parameters];

    [request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
        NSDictionary* user = (NSDictionary *)result;
        if (!error) {
            // process profile info if needed
        }
        else {
            // First time an error occurs, FB SDK will attemt to recover from it automatically
            // via FBSDKGraphErrorRecoveryProcessor (see documentation)

            // you can process an error manually, if you wish, by setting
            // -setGraphErrorRecoveryDisabled to YES

            NSInteger statusCode = [(NSString *)error.userInfo[FBSDKGraphRequestErrorHTTPStatusCodeKey] integerValue];
            if (statusCode == 400) {
                // access denied
            }
        }
    }];
}

Each time you think it is good time to check FB token (e.g. an app was in background for a while), call -requestFacebookUserInfo. This will submit Open Graph request and returns an error if token is invalid/expired.

like image 161
Yevhen Dubinin Avatar answered Apr 01 '23 12:04

Yevhen Dubinin