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: 

How to migrate to new Auth workflow with python SDK while minimizing need for single user input?

How to migrate to new Auth workflow with python SDK while minimizing need for single user input?

FrancoisNOYEZ
Explorer | Level 4
Go to solution

Hello Dropbox team,

 

I have set up a small app as a python script which runs continuously on my server, and which needs to read some files that I store on my Dropbox storage space, in the folder dedicated to this app. This script needs to read those files at regular interval (currently every 15 minutes). When I set up this app, I generated a token that I now provide to my python script every time I need to launch it. Things have been working fine up until now.

 

I have been warned of the API update, notably related to authentication, by an email in November 2020.
Now I'm tring to see if I need to change something to my app in order to adapt to this update, and if yes, to implement that change.
However it has been difficult to find out if I need to do something, and if yes, what.
If I understand properly what I read on this page (https://developers.dropbox.com/fr-fr/oauth-guide), as long as only me is using this app, I can use a token generated in the OAuth 2 Section of the Setting menu of my app, and set its expiration setting to 'No expiration'. However, in the help box, it is said that such tokens will be deprecated in the future, so if possible I'd like to anticipate that.
When I look at the table at the end of this page, in the "Summary" section, if I parse it properly, my app falls within the "A server-side application that requires background access." category, which means what I should "Use the OAuth code flow, with refresh tokens.".
The thing is, I'm not sure of how to do that. When I look at examples available here (https://www.dropbox.com/developers/reference/getting-started?_tk=guides_lp&_ad=tutorial5&_camp=get_s...), seems like it's just using the long-lived token method that I'm already using.
I found some examples script for the python SDK here (https://github.com/dropbox/dropbox-sdk-python/tree/main/example/oauth) but I'm not sure which one to follow.
From what I can see, I will always need to interact with the script every time I launch it, in order to copy the authorization code and provide it to the script, is that right?

 

Basically my question is: what is the script setup that I need to do, that will minimize the interaction with Dropbox required from me, while making sure that my app is still functional and compliant with Dropbox's future deprecation, for the time being?

1 Accepted Solution

Accepted Solutions

Greg-DB
Dropbox Staff
Go to solution

@FrancoisNOYEZ  Здравко is correct, under the new system you do not need to interact with your script every time it runs. You can supply it the refresh token like you previously supplied it a long-lived access token and it will automatically run without manual user interaction, as before.

 

You do need to process the app authorization flow one time to get a refresh token though. You can refer to this example to see how to process the app authorization flow to get a refresh token, at which point you can then set up a client using it, as shown at the end of the example.

View solution in original post

13 Replies 13

Здравко
Legendary | Level 20
Go to solution

@FrancoisNOYEZ wrote:
...

From what I can see, I will always need to interact with the script every time I launch it, in order to copy the authorization code and provide it to the script, is that right?

...

Hi @FrancoisNOYEZ,

No, that's NOT right. 😉 Relax. 🙂

You can migrate to OAuth2 and you will need to interact to your script only for the long lived token - refresh token (i.e. at the beginning), nothing more! This token doesn't expire - the same like before (almost). The only difference is that it can't be used directly in API calls. The its only purpose is generation of short living tokens - access token, usable within API calls. You usually should not take care of this process, since it's performed in the SDK (internally) and you can continue usage of SDK's calls in the same way as before. When need new token will be generated on demand without your additional interaction. SDK will call /oauth2/token for you. Might be need little bit more care if you call on some place(s) API calls directly, bypassing SDK.

Hope this helps to some extent.

Greg-DB
Dropbox Staff
Go to solution

@FrancoisNOYEZ  Здравко is correct, under the new system you do not need to interact with your script every time it runs. You can supply it the refresh token like you previously supplied it a long-lived access token and it will automatically run without manual user interaction, as before.

 

You do need to process the app authorization flow one time to get a refresh token though. You can refer to this example to see how to process the app authorization flow to get a refresh token, at which point you can then set up a client using it, as shown at the end of the example.

FrancoisNOYEZ
Explorer | Level 4
Go to solution

Hello @Здравко, @Greg-DB,

 

Thank you for your answers.
Following your indications, as well as the example described in the examples scripts, I was able to define a "refresh token", and I indeed see that I only need to supply it, along with the APP_KEY and APP_SECRET, when instantiating a Dropbox class object. As long as I keep the 'oauth2_access_token_expiration' parameter equal to none, when carrying out this instantiation, I guess I will never need to perform new authentication operations, is that right?

 

With this new authentication scheme, we went from having to just specify a single token, to having to specify the APP_KEY, APP_SECRET, and refresh token. In terms of management of this sensitive authentication data, in your opinion, how should I proceed? I used to pass along the authentication token as a parameter to the command used to launch my script ('cause I don't want to write it down in my script). Is it ok to do something similar now (the difference being that I'll have to provide 3 values instead of one)? Seems like, as long as I keep those authentication -needed data in the same spot, nothing much was gained in terms of security (though now the scope associated to the token is read-only, so that seems like an improvement here). How could I improve the way I manage those data, if possible, in your opinion?

Здравко
Legendary | Level 20
Go to solution

@FrancoisNOYEZ wrote:
... As long as I keep the 'oauth2_access_token_expiration' parameter equal to none, when carrying out this instantiation, I guess I will never need to perform new authentication operations, is that right?
...

Hi @FrancoisNOYEZ,

In the practice, yes, most probably. If we should be more general, there are situations where refresh token could be revoked (both explicitly, by your or another person having access to the account, or implicitly, by some actions, which shouldn't happen in normal case). Even very unlikely, it's good practice to expect such a situation in your code (script or other). When something goes wrong and the token gets revoked, somehow, just inform/warn in suitable way, at least. The same is valid for long lived access token, used by you till now. 😉 Just a good practice that can make your life easy sometimes!

 


@FrancoisNOYEZ wrote:
... In terms of management of this sensitive authentication data, in your opinion, how should I proceed? I used to pass along the authentication token as a parameter to the command used to launch my script ('cause I don't want to write it down in my script). Is it ok to do something similar now (the difference being that I'll have to provide 3 values instead of one)? ...

🙄🙂😁@FrancoisNOYEZ, If you care for data (of any kind) and don't want other process (and people accordingly) to touch it, command line is the worst place to pass such data (or not the best, definitelly, at least)! Command name a all options and parameters are object of logging in the shell history, at least. The same information is accessible through system tool for process monitoring (how exactly depends on exact OS in use, but accessible). Other ways are also possible! What think that you are hiding in such a way?!!! Be careful!

If I'm in your shoes, will look around your system and usually there is some sort of system "wallet". That's exactly what this service is dedicated for! Exact form is OS dependent, but generally there is some encrypted, system controlled storage where every application could reserve some space. There you can store sensitive data of your choice (like discussing here). The access is system controlled and one application can't touch data of other one and also the same application running on different account is restricted (there are different storage places). 😉 The just mentioned would be my choice.

The needed data representation can be stored on and received from a secure place (like the wallet above). On start, when available, could be used directly to instantiate Dropbox client object. When missing OAuth flow could run and result received will be used both for client instantiation and storage of sensitive data.

Hope this gives useful directions.

 

PS: For a almost platform independent way in Python try the "keyring" package. 😉 It behaves as a interface to corresponding installed system service. Or tries to, at least, and succeeds when there is available proper backend. Linux, Mac, and Windows are generally supported.

FrancoisNOYEZ
Explorer | Level 4
Go to solution

Hello Здравко

 

Thank you for your insights.

 

Ok, so barring voluntary revocation by someone, or some actions taken by DropBox, the refresh token should be valid indefinitely. At the very least, with it and the way I created it, I should be able to use it with the same level of 'no action' that I currently have with the use of the 'overall' access token.
I agree that it would be better if my app was able to react properly to the token being revoked or becoming non-functional; I'll see what I can do about that in the future.

 

Well, I never said it was secure, I just said that I did not want to hardcode the access variables in the program (since I use control version, notably). Though, arguably, from what you are describing, using the command line to pass the secret seems like it's actually worse than hardcoding it in the program. I asked the question because I wanted to finally take the time to do something better with that respect : )
Thank you for the suggestion, I'll look into that, notably this 'keyring' package that you mentioned.

tszikszai
Explorer | Level 3
Go to solution

I have been struggling with getting a refresh token and I was able to run your example successfully so that is great thank you!!  But what I am still struggling with are two things:  1) How do I get the refresh token out of this and 2) how do I use it in my python code to actually log into dropbox and automatically use a file.  For example with a regular token I use the below code, but the problem with the regular token is that it keeps expiring.  So what do I replace this code with???:

 

dbx = dropbox.Dropbox(access_token)
with open(local_file_path, 'rb') as f:
dbx.files_upload(f.read(), dropbox_path, mode=dropbox.files.WriteMode.overwrite)


 

 

Здравко
Legendary | Level 20
Go to solution

Hi @tszikszai,

You can take a look here for a working example. It targets different task, but you can get the object in dbx variable using getClient method instead of initializing by your own. In such a way everything, regarding OAuth flow, is done and you can use the result. 😉 Of course you can change whatever needed. So, your code would look like:

from <whatever you named the file> import ApplicationConfig
conf = ApplicationConfig()
dbx = conf.getClient()
with open(local_file_path, 'rb') as f:
    dbx.files_upload(f.read(), dropbox_path,
                     mode=dropbox.files.WriteMode.overwrite)

 ... or something similar. Isn't simpler? 😀 Just a note: While you can call getClient multiple times, conf object should be single one on global (or other) place/scope visible whenever need to be get a client. It should alive to the end of Dropbox API usage (usually end of the script).

Hope this helps.

Greg-DB
Dropbox Staff
Go to solution

@tszikszai I see Здравко helpfully provided some sample code. For additional reference, you can find the documentation for the OAuth2FlowNoRedirectResult object here, which is returned by OAuth2FlowNoRedirectResult. There's also an example of how to get the refresh token in particular out of that object and pass it into a Dropb....

tszikszai
Explorer | Level 3
Go to solution

Thank you for all this!!  The first part of the example works, however I am still struggling.  I was able to get a REFRESH_TOKEN.  However where I run into trouble is when I am trying to use the REFRESH_TOKEN to replace an expired ACCESS_TOKEN.  So for example when I run this code and it shows that the ACCESS_TOKEN expired:

 

dbx = dropbox.Dropbox(ACCESS_TOKEN)
try:
dbx.users_get_current_account()
print('Dropbox connection successful')
except AuthError as e:

 

This throws an exception as my current ACCESS_TOKEN has expired.  So I try to do this to replace it with a new one but it does not work:

 

auth_flow = dropbox.DropboxOAuth2FlowNoRedirect(APP_KEY, APP_SECRET)
try:
new_access_token, _ = auth_flow.refresh_access_token(REFRESH_TOKEN)

Or also tried this and this does not work either:

 

dbx = dropbox.Dropbox(APP_KEY, oauth2_access_token=ACCESS_TOKEN)

try:
# Use the refresh token to obtain a new access token
new_access_token, refresh_token = dbx.oauth2_token_refresh(REFRESH_TOKEN)

 

I keep getting exceptions and never able to replace the expired access token and get a new_access_token.  What am I doing wrong?  As I said the first part of the code worked, and I created a brand new app and went through the OAuth flow and have the APP_KEY, APP_SECRET and REFRESH_TOKEN, so I just don't see what I am doing wrong.  I feel I am missing something fundamental here.

Need more support?
Who's talking

Top contributors to this post

  • User avatar
    tszikszai Explorer | Level 3
  • User avatar
    Greg-DB Dropbox Staff
What do Dropbox user levels mean?