cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Announcements
Want to learn some quick and useful tips to make your day easier? Check out how Calvin uses Replay to get feedback from other teams at Dropbox here.

Dropbox API Support & Feedback

Find help with the Dropbox API from other developers.

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Re: migrating from API 1 to 2 - how do I know if I have OAuth 1 tokens?

migrating from API 1 to 2 - how do I know if I have OAuth 1 tokens?

Bob S.15
Collaborator | Level 9

I am finally getting around to updating my OLD apps from the original Dropbox IOS API to the new one. I'm looking at the migration guide, and the first thing it says is to check my OAuth tokens to see if they are version 1 or 2.  How do I know which I have? 

 

Also, the migration guide describes using the "endpoint" /oauth2/token_from_oauth1 to transition old tokens.  So, I am coming to this from an ancient time -- what is an "endpoint", and is this 'token_from_oauth1' a function that you call from Objective-C in an iOS app?  The documentation page I'm looking at only shows Python, Java, Ruby, and PHP examples, so maybe I'm not looking in the right place.

 

Is this where I should start?  Is there a guide for upgrading an iOS app somewhere?

 

Also is this page current?  It dates from March 2016,  but then also there is a v1 deprecation warning at the top of it:

https://www.dropbox.com/developers-v1/core/sdks/ios

 

Thanks,

Bob

 

54 Replies 54

Bob S.15
Collaborator | Level 9

Hey Greg,

 

   I don't really see anything in this Getting Started about tokens or extracting them? https://github.com/dropbox/dropbox-sdk-obj-c#get-started

 

I don't understand where these tokens come into it.  It seems like if I just follow the authorization flow as described in "Getting Started", it would authorize the app?

 

EDIT:  If you saw that earlier post about the 'image not found' error, I fixed that.  I didn't have the framework as an embedded binary...

 

 

Thanks!

Bob

 

 

Greg-DB
Dropbox Staff

Hi Bob, yes, if you just follow the getting started guide you linked to, that will have you implement the app authorization flow, allowing users to link to and use your app. That will handle getting new tokens for you and storing them.

 

It's only if you were using an old SDK and want to automatically migrate the previously stored access tokens from that in your app would you need to put in the extra work to do so, e.g., using the technique from this old blog post.

Bob S.15
Collaborator | Level 9

Hey Greg,

 

   I have a couple of questions about the regular authorization flow.  If I don't have pre-existing tokens, I'm using the web form login to authorize the user.   It put up a screen that says "<AppName> would like access to its own folder, Apps->AppName, inside your Dropbox, Learn More." and you can click Cancel or Allow.

 

If I click Allow, instead of returning to the app immediately, it shows a pop-up dialog that says "Open in "AppName"?" and you again have to press Cancel or Open.  That seems wrong.  Is it really required to do that second dialog or am I doing something wrong?

 

Also, once I have done this, how to I get it to remember that it is logged into the app?  Currently I have to go through this authorization every time I run the app.

 

Thanks,

Bob

 

Greg-DB
Dropbox Staff
That "Open in" confirmation is part of iOS itself and was introduced by Apple somewhat recently (either iOS 9 or iOS 10 if I recall correctly) in order to let the user prevent unwanted redirects between apps. Consequently, that is expected, and we don't have control over it.

Also, the SDK should automatically store the authorization for you. Did you finish setting up the authorization flow as documented in the guide? Are you getting any errors?

Bob S.15
Collaborator | Level 9

Hey Greg,

 

  I have the authorization flow set up -- but the Getting Started guide only describes how to authorize the user, it doesn't say anything about handling when the authorization has already happened.  By looking at the DBRoulette example, it looks like I should check  [DropboxClientsManager authorizedClient], is that right?  If that is not nil then the user is already authorized?

 

My old app used to authorize and then get the user's account info.  How would I do that with the new SDK?   I see this Account structure here:

https://dropbox.github.io/dropbox-sdk-obj-c/api-docs/latest/Classes/DBUSERSAccount.html

But it isn't clear how to use the SDK to obtain the information?  Is there an example somewhere of how to obtain the account info?

 

Thanks,

Bob

 

Greg-DB
Dropbox Staff

Yes, that's right, you should use authorizedClient like that.

 

You can use the DBUSERSRoutes.getCurrentAccount method to get the account information.

 

That would look like this:

[[client.usersRoutes getCurrentAccount] response:^(DBUSERSFullAccount *account, DBNilObject *_, DBRequestError *error) {
    if (account) {
        NSLog(@"%@", account);
    } else if (error) {
        NSLog(@"%@", error);
    }
}];

(Note that DBError was renamed to DBRequestError in 2.0.6, so make sure you use the right one, depending on what version you're using.)

 

Bob S.15
Collaborator | Level 9

Okay, thanks.

 

Also I wanted to ask you about retrieving old tokens.  Now that I know the user can just re-authorize, it's not that big a deal, but I was trying to get it to work anyway.  

 

My old phone is logged into Dropbox using the old version of the app.  Then I run the new version to see if I can convert the old tokens.  The new version does not recognize that the user is logged in already, which is expected.  Then I call this:

 

NSArray *credentials = [bigApp getTokensFromSyncAPI];                    

 

But [credentials count] always returns 0.  Shouldn't it return the old tokens?

 

Thanks

Bob

Greg-DB
Dropbox Staff

That code is written for getting tokens from the Sync SDK, but you're using the Core SDK, so the values would be a little different.

 

I put this together for you as a basic concept of how this would work for going from the Core SDK to the API v2 Objective-C SDK:

 

- (NSArray * )getTokensFromCoreSDK
{
    NSString *keychainPrefix = [[NSBundle mainBundle] bundleIdentifier];
    NSString *keychainId = [NSString stringWithFormat:@"%@.dropbox.auth", keychainPrefix];
    NSDictionary *keychainDict = @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
                                   (__bridge id)kSecAttrService: keychainId,
                                   (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne,
                                   (__bridge id)kSecReturnAttributes: (__bridge id)kCFBooleanTrue,
                                   (__bridge id)kSecReturnData: (__bridge id)kCFBooleanTrue};

    CFDictionaryRef result = NULL;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)keychainDict,
                                          (CFTypeRef * )&result);
    NSDictionary *attrDict = (__bridge_transfer NSDictionary * )result;
    NSData *foundValue = [attrDict objectForKey:(__bridge id)kSecValueData];
    NSMutableArray *credentials = [[NSMutableArray alloc] init];

    if (status == noErr && foundValue) {
        NSDictionary *savedCreds = [NSKeyedUnarchiver unarchiveObjectWithData:foundValue];
        NSArray *credsForApp = [savedCreds objectForKey:@"kDBDropboxUserCredentials"];
        for (NSDictionary *credsForUser in credsForApp) {
            NSDictionary *token = @{
                                    @"userId": [credsForUser objectForKey:@"kDBDropboxUserId"],
                                    @"token": [credsForUser objectForKey:@"kMPOAuthCredentialAccessToken"],
                                    @"tokenSecret": [credsForUser objectForKey:@"kMPOAuthCredentialAccessTokenSecret"]
                                    };
            [credentials addObject:token];
        }
    }
    return credentials;
}

- (void)getAndSaveOAuth2TokensFromRetrievedOAuth1Tokens:(NSArray * )oauth1Tokens
{

    DBTransportClient *transportClient = [[DBTransportClient alloc] initWithAccessToken:nil selectUser:nil userAgent:nil delegateQueue:nil forceForegroundSession:nil appKey:APP_KEY appSecret:APP_SECRET];
    DropboxClient *client = [[DropboxClient alloc] initWithTransportClient:transportClient];

    for (NSDictionary *oauth1Token in oauth1Tokens) {
        [[client.authRoutes tokenFromOauth1:[oauth1Token objectForKey:@"token"] oauth1TokenSecret:[oauth1Token objectForKey:@"tokenSecret"]] response:^(DBAUTHTokenFromOAuth1Result *result, DBAUTHTokenFromOAuth1Error *routeError, DBRequestError *error) {
            if (result) {
                NSLog(@"OAuth 2 access token: %@\n", result.oauth2Token);
                DBAccessToken *accessToken = [[DBAccessToken alloc] initWithAccessToken:result.oauth2Token uid:[oauth1Token objectForKey:@"userId"]];
                [[DBOAuthManager sharedOAuthManager] storeAccessToken:accessToken];
            } else {
                NSLog(@"%@\n%@\n", routeError, error);
            }
        }];
    }

}

...

NSArray *oauth1Tokens = [self getTokensFromCoreSDK];
[self getAndSaveOAuth2TokensFromRetrievedOAuth1Tokens: oauth1Tokens];

I haven't tested that extensively, so be sure to test it well in your app. I hope it helps though!

 

 

Bob S.15
Collaborator | Level 9

Hey Greg,

 

  That's great, thanks!  That code works, but I think I am missing one step.  After I go through and store the new tokens, how do I get it to recognize that it is authorized?  I am finding that [DropboxClientsManager authorizedClient] is returning nil after storing the tokens.  If I quit the app and then run it again, THEN it recognizes the app as being authorized.  But how do I get it to know it's authorized without having to restart the app?

 

Another question if you do not mind.  I am making progress with the SDK and have been able to upload files.  But I don't understand why some DBFILESRoutes functions list two arguments for the return response, but they seem to require three in practice.  For example -createFolder:autorename says it returns a DBFILESFolderMetadata object and a DBFILESCreateFolderError object, but XCode gives me an error unless there is also a third DBRequestError object.  Is this a documentation mistake or is the third argument assumed but not shown for some reason?

 

 

Thanks!

Bob

Greg-DB
Dropbox Staff

I believe you can get that active within the same session using DropboxClientsManager.reauthorizeClient. Let me know if that doesn't work for you though.

 

Yes, the third one, a DBRequestError, applies to all calls and covers higher level failures (network issues, invalid access tokens, etc.) so it's not documented on each call individually.

Need more support?