oauth-2.0tokenbox-apiboxboxapiv2

iPhone - Box SDK/API 20000 error followed by 20002 Error - Authentication tokens are not refreshing


I have seen a lot of different posts about how to solve this problem, but I have had no luck. I have tried the heartbeat solution, and it does nothing. I know that my keychain is storing my refresh token, but it is not serving any use.

Steps:

  1. Start app
  2. Go to load directory (root in this case)
  3. Get this error:

EDIT: First I get a 20000 error. It seems my authentication tokens are not refreshing.

Error Domain=com.box.sdk.errordomain Code=20002 "The operation couldn’t be completed. (com.box.sdk.errordomain error 20002.)"

  1. Go through Box login process again.
  2. Reload tableview
  3. Works.

I am using this code to refresh my access tokens (I think it is supposed to)

if (storedRefreshToken)
    {
        [BoxSDK sharedSDK].OAuth2Session.refreshToken = storedRefreshToken;
    }

I feel like I am missing something here also.

I need my user to stay logged in for the allowed 14 days. How can I get the app login state to survive app restarts?

I am using the latest V2 SDK.

EDIT:

I have tried everything, from refreshing the refreshtoken in the keychain on each ViewController to referencing the AppDelegate. I can't get it to stay logged in and just keep getting the 20002 error when I start the app again (not resume, but cold start). I don't want to use the Box filepicker, but I want to make my own tableview. Any other ideas out there?

AppDelegate:
in didFinishLaunching:
    [BoxSDK sharedSDK].OAuth2Session.clientID = @"XXXXXXXXXX";
        [BoxSDK sharedSDK].OAuth2Session.clientSecret = @"XXXXXXX";

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(boxAPITokensDidRefresh:) name:BoxOAuth2SessionDidBecomeAuthenticatedNotification object:[BoxSDK sharedSDK].OAuth2Session];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setRefreshTokenInKeychain:) name:BoxOAuth2SessionDidRefreshTokensNotification object:[BoxSDK sharedSDK].OAuth2Session];

    // set up stored OAuth2 refresh token
    _keychain = [[KeychainItemWrapper alloc] initWithIdentifier:REFRESH_TOKEN_KEY accessGroup:nil];

    id storedRefreshToken = [_keychain objectForKey:(__bridge id)kSecValueData];
    if (storedRefreshToken)
    {
        [BoxSDK sharedSDK].OAuth2Session.refreshToken = storedRefreshToken;
    }

listener methods

- (void)boxAPITokensDidRefresh:(NSNotification *)notification
{
    BoxOAuth2Session *OAuth2Session = (BoxOAuth2Session *) notification.object;
    [self setRefreshTokenInKeychain:OAuth2Session.refreshToken];
    _isBox = YES;
    [self removeBoxLoginViewController];
}

- (void)setRefreshTokenInKeychain:(NSString *)refreshToken
{
    [_keychain setObject:@"MyApp" forKey: (__bridge id)kSecAttrService];
    [_keychain setObject:refreshToken forKey:(__bridge id)kSecValueData];
    NSLog(@"refreshToken: %@", refreshToken);
}

Main ViewController: 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(boxAPIAuthenticationRefreshToken:) name:BoxOAuth2SessionDidReceiveRefreshErrorNotification object:[BoxSDK sharedSDK].OAuth2Session];
[self boxAPIHeartbeat];

Heartbeat:

- (void)boxAPIHeartbeat
{
    [[BoxSDK sharedSDK].foldersManager folderInfoWithID:@"0" requestBuilder:nil success:nil failure:nil];
}

ListenerMethods after hearbeat:

- (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.tableView reloadData];
}

- (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)boxAPIAuthenticationRefreshToken:(NSNotification *)notification
{
    BoxOAuth2Session *OAuth2Session = (BoxOAuth2Session *) notification.object;
    [self setRefreshTokenInKeychain:OAuth2Session.refreshToken];
    NSLog(@"REFRESH TOKEN: %@", OAuth2Session.refreshToken);
}
//trying this out????
- (void)setRefreshTokenInKeychain:(NSString *)refreshToken
{
    [_keychain setObject:@"MyApp" forKey: (__bridge id)kSecAttrService];
    [_keychain setObject:refreshToken forKey:(__bridge id)kSecValueData];
    NSLog(@"refreshToken: %@", refreshToken);
}

I can't use the Box SDK if I can't get this figured out this weekend. I would think Box would want their SDK to be used by developers, but the documentation is so poor. What am I missing? I just want the app to stay logged in through cold starts!


Solution

  • It turns out, that the issue was with the ARC version of Keychain. I noticed this when I started placing NSLogs all over the place and noticed that the refreshToken getting returned at app launch, was not the refreshToken that was getting encoded into the Keychain. I replaced the ARC Keychain files with the ones from the sample app and put the ARC flag in, and it is working perfectly.