Reputation: 9035
The box.com SDK for iOS has an object called sharedSDK
that holds another object called OAuth2Session
. OAuth2Session
has a property called isAuthorized
. On each application launch this property is set to NO
. Even if I keep the refreshToken
inside the system Keychain, and assign it at launch like so:
//...applicationDidFinisLaunching...
NSString *token = [controllerObject fetchFromKeychainForKey:@"com.box.token"];
[BoxSDK sharedSDK].OAuth2Session.refreshToken = token;
if ([BoxSDK sharedSDK].OAuth2Session.isAuthorized) {
//Not until signing in
NSLog(@"Authorized.)";
} else {
NSLog(@"Not Authorized.");
}
What should I be doing differently to check auth status? The Dropbox SDK has a method to determine if the session is linked, persists through launches.
Upvotes: 2
Views: 1349
Reputation: 231
I'm the author of the iOS SDK. The isAuthorized
method is only a best guess of whether or not the current OAuth2 tokens are valid. From the documentation:
Compares accessTokenExpiration to the current time to determine if an access token may be valid. This is not a guarantee that an access token is valid as it may have been revoked or already refreshed.
Because accessTokenExpiration
is not stored anywhere by the Box iOS SDK, this field will be nil following initialization, even if the refresh token is loaded.
The Box iOS SDK takes the stance that the Box API is the source of truth about state and does not attempt to perform client side checks that can be handled more reliably by the server.
The recommended way of reloading the OAuth2 session is to set the refresh token from the keychain as you have done and then issue a "heartbeat" API call to trigger an autorefresh or fail if the refresh token is invalid.
An example of this can be found in the Box iOS SDK sample app
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(boxAPIAuthenticationDidSucceed:)
name:BoxOAuth2SessionDidBecomeAuthenticatedNotification
object:[BoxSDK sharedSDK].OAuth2Session];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(boxAPIAuthenticationDidFail:)
name:BoxOAuth2SessionDidReceiveAuthenticationErrorNotification
object:[BoxSDK sharedSDK].OAuth2Session];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(boxAPIInitiateLogin:)
name:BoxOAuth2SessionDidReceiveRefreshErrorNotification
object:[BoxSDK sharedSDK].OAuth2Session];
// attempt to heartbeat. This will succeed if we successfully refresh
// on failure, the BoxOAuth2SessionDidReceiveRefreshErrorNotification notification will be triggered
[self boxAPIHeartbeat];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)boxAPIHeartbeat
{
[[BoxSDK sharedSDK].foldersManager folderInfoWithID:BoxAPIFolderIDRoot requestBuilder:nil success:nil failure:nil];
}
#pragma mark - Handle OAuth2 session notifications
- (void)boxAPIAuthenticationDidSucceed:(NSNotification *)notification
{
NSLog(@"Received OAuth2 successfully authenticated notification");
BoxOAuth2Session *session = (BoxOAuth2Session *) [notification object];
NSLog(@"Access token (%@) expires at %@", session.accessToken, session.accessTokenExpiration);
NSLog(@"Refresh token (%@)", session.refreshToken);
[self dismissViewControllerAnimated:YES completion:nil];
BOXAssert(self.viewControllers.count == 1, @"There should only be one folder in the hierarchy when authentication succeeds");
BoxFolderViewController *rootVC = (BoxFolderViewController *)self.topViewController;
[rootVC fetchFolderItemsWithFolderID:BoxAPIFolderIDRoot name:@"All Files"];
}
- (void)boxAPIAuthenticationDidFail:(NSNotification *)notification
{
NSLog(@"Received OAuth2 failed authenticated notification");
NSString *oauth2Error = [[notification userInfo] valueForKey:BoxOAuth2AuthenticationErrorKey];
NSLog(@"Authentication error (%@)", oauth2Error);
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)boxAPIInitiateLogin:(NSNotification *)notification
{
NSLog(@"Refresh failed. User is logged out. Initiate login flow");
dispatch_sync(dispatch_get_main_queue(), ^{
[self popToRootViewControllerAnimated:YES];
NSURL *authorizationURL = [BoxSDK sharedSDK].OAuth2Session.authorizeURL;
NSString *redirectURI = [BoxSDK sharedSDK].OAuth2Session.redirectURIString;
BoxAuthorizationViewController *authorizationViewController = [[BoxAuthorizationViewController alloc] initWithAuthorizationURL:authorizationURL redirectURI:redirectURI];
BoxAuthorizationNavigationController *loginNavigation = [[BoxAuthorizationNavigationController alloc] initWithRootViewController:authorizationViewController];
authorizationViewController.delegate = loginNavigation;
loginNavigation.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:loginNavigation animated:YES completion:nil];
});
}
This view controller registers for OAuth2 notifications which are triggered in the event of a successful refresh or a logout. In the selectors you register for these callbacks, you can load a view controller in your app or load the BoxAuthorizationViewController to log a user in.
Upvotes: 3