facebook / facebook-ios-sdk

Used to integrate the Facebook Platform with your iOS & tvOS apps.
https://developers.facebook.com/docs/ios
Other
7.75k stars 3.51k forks source link

`FBSDKAuthenticationToken.current` returns the actual valid authentication token only after a certain delay #2417

Open GalBerezansky opened 2 months ago

GalBerezansky commented 2 months ago

Checklist before submitting a bug report

Xcode version

15.2

Facebook iOS SDK version

17.0.1

Dependency Manager

Prebuilt Binaries

SDK Framework

Login

Goals

I want to use FBSDKAuthenticationToken.currentAuthenticationToken when the user opens the application, this user has logged-in with the limited log-in in a previous session and I'd like to use his authentication token.

Expected results

To get a non-nil FBSDKAuthenticationToken.currentAuthenticationToken whenever it is called, it happens after the set-up of the facebook-ios-sdk, the facebook-ios-sdk should be useable at that time.

Actual results

In reality FBSDKAuthenticationToken.currentAuthenticationToken is nil when I first access it, I get the non-nil valid value only with a retry mechanism. With solid internet connection I get the non-nil auth token only after 0.4 seconds after the first call to the the method approximately.

The main issue is I don't know when the user is actually logged-out and when the authentication token in nil because of this delay, if the user logs-out via facebook's side I'll just run my retry mechanism until I reach time out.

It is worth noting that the exact same issue occurs with FBSDKAccessToken.currentAccessToken in the non-limited regular log-in. When I used version 12.3.1 of the sdk I got the valid non-nil value as soon as I accessed it, now I get the same delay there.

The currentAuthenticationToken isn't well documented, it isn't clear when it should be nil or not, it feels like there was a behavior change under the hood.

Bottom line, please explain when and why the authentication token is nil, when should I decide that the user is actually logged-out and when I need to wait/retry, an even better solution is to ensure that the FBSDKAuthenticationToken.currentAuthenticationToken and FBSDKAccessToken.currentAccessToken are accessible as soon as possible whenever they have a value, otherwise doc them to explain how they should be used.

Thanks!

Steps to reproduce

  1. Successfully log-in with the limited facebook log-in.
  2. Close the application.
  3. Re-open it, the first access to FBSDKAuthenticationToken.currentAuthenticationToken is nil even though the user should be logged-in.

Code samples & details

// The code the does the facebook log-in
- (void)loginWithPresentingViewController:(UIViewController *)presentingViewController
                                    block:(void(^)(NSString * _Nullable token, BOOL cancelled,
                                                   NSError * _Nullable error))block {
  auto configuration =
      [[FBSDKLoginConfiguration alloc] initWithPermissions:@[@"public_profile", @"email"]
                                                  tracking:FBSDKLoginTrackingLimited];
  dispatch_async(dispatch_get_main_queue(), ^{
    [self.loginManager logInFromViewController:presentingViewController
                                 configuration:configuration
                                    completion:^(FBSDKLoginManagerLoginResult * _Nullable result,
                                                 NSError * _Nullable error) {
      if (!result || result.isCancelled) {
        block(nil, result.isCancelled ?: NO, error);
        return;
      }

      if (![self.loginPermissions isSubsetOfSet:nn(result.grantedPermissions)]) {
        block(nil, NO, [NSError lt_errorWithCode:FORErrorCodeLoginFailed description:@"An error occured");
        return;
      }

      block(nn(result.authenticationToken.tokenString), NO, nil);
    }];
  });
}

// The code that returns a `nil` authentication token.
- (void)loginStatusWithBlock:(void(^)(FORLoginSourceLoginStatus *tokenStatus,
                                      NSString * _Nullable token, NSError * _Nullable error))block {
  auto _Nullable currentAuthenticationToken = FBSDKAuthenticationToken.currentAuthenticationToken; // Here I get `nil` even though the user has successfully logged-in in the previous session. 
  if (currentAuthenticationToken) {
    auto loginStatus = currentAuthenticationToken.lt_isActive ?
        $(FORLoginSourceLoginStatusLoggedIn) : $(FORLoginSourceLoginStatusLoginExpired);
    block(loginStatus, nn(currentAuthenticationToken.tokenString), nil);
  } else {
    block($(FORLoginSourceLoginStatusNotLoggedIn), nil, nil);
  }
}

// The code that enables getting the non-nil authentication token with the retry mechanism.
- (void)loginStatusWithBlock:(void(^)(FORLoginSourceLoginStatus *tokenStatus,
                                      NSString * _Nullable token, NSError * _Nullable error))block {
  __block uint attempt = 0;
  dispatch_queue_t queue = dispatch_queue_create("some queue", DISPATCH_QUEUE_SERIAL);

  __block void (^retryRetrieveFacebookAccessTokenBlock)(void) = [^{
    /// Works only after a few retries, approximately 4 retries in my case. 
    auto _Nullable currentAuthenticationToken = FBSDKAuthenticationToken.currentAuthenticationToken;
    if (currentAuthenticationToken) {
      /// Here I parse the JWT token to check if the token is expired or not.
      auto loginStatus = currentAuthenticationToken.lt_isActive ?
          $(FORLoginSourceLoginStatusLoggedIn) : $(FORLoginSourceLoginStatusLoginExpired);
      block(loginStatus, nn(currentAuthenticationToken.tokenString), nil);
    } else if (attempt < FORFacebookLoginSource.kMaxRetrieveFacebookAccessTokenRetryCount) {
      ++attempt;
      dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC));
      dispatch_after(delay, queue, retryRetrieveFacebookAccessTokenBlock);
    } else {
      block($(FORLoginSourceLoginStatusNotLoggedIn), nil, nil);
      return;
    }
  } copy];

  retryRetrieveFacebookAccessTokenBlock();
}

+ (uint)kMaxRetrieveFacebookAccessTokenRetryCount {
  return 20;
}
tzuyangliu commented 2 months ago

Same issue

GalBerezansky commented 1 month ago

An update after updating to 17.0.2:

This issue persists. Have there been any updates or efforts made to resolve it? Currently, it is hindering our migration process. Thanks!

GalBerezansky commented 2 weeks ago

Any update?