3030 url_encode = urllib .urlencode # pylint: disable=no-member,useless-suppression
3131
3232TOKEN_ACCESS_TYPES = ['offline' , 'online' , 'legacy' ]
33+ INCLUDE_GRANTED_SCOPES_TYPES = ['user' , 'team' ]
3334
3435class OAuth2FlowNoRedirectResult (object ):
3536 """
@@ -39,17 +40,22 @@ class OAuth2FlowNoRedirectResult(object):
3940 in using them, please contact Dropbox support
4041 """
4142
42- def __init__ (self , access_token , account_id , user_id , refresh_token , expiration ):
43+ def __init__ (self , access_token , account_id , user_id , refresh_token , expiration , scope ):
4344 """
4445 Args:
4546 access_token (str): Token to be used to authenticate later
4647 requests.
48+ refresh_token (str): Token to be used to acquire new access token
49+ when existing one expires
50+ expiration (int, datetime): Either the number of seconds from now that the token expires
51+ in or the datetime at which the token expires
4752 account_id (str): The Dropbox user's account ID.
4853 user_id (str): Deprecated (use account_id instead).
4954 refresh_token (str): Token to be used to acquire new access token
5055 when existing one expires
5156 expiration (int, datetime): Either the number of seconds from now that the token expires
5257 in or the datetime at which the token expires
58+ scope (list): list of scopes to request in base oauth flow.
5359 """
5460 self .access_token = access_token
5561 if not expiration :
@@ -61,14 +67,16 @@ def __init__(self, access_token, account_id, user_id, refresh_token, expiration)
6167 self .refresh_token = refresh_token
6268 self .account_id = account_id
6369 self .user_id = user_id
70+ self .scope = scope
6471
6572 def __repr__ (self ):
66- return 'OAuth2FlowNoRedirectResult(%s, %s, %s, %s, %s)' % (
73+ return 'OAuth2FlowNoRedirectResult(%s, %s, %s, %s, %s, %s )' % (
6774 self .access_token ,
6875 self .account_id ,
6976 self .user_id ,
7077 self .refresh_token ,
7178 self .expires_at ,
79+ self .scope ,
7280 )
7381
7482
@@ -77,7 +85,8 @@ class OAuth2FlowResult(OAuth2FlowNoRedirectResult):
7785 Authorization information for an OAuth2Flow with redirect.
7886 """
7987
80- def __init__ (self , access_token , account_id , user_id , url_state , refresh_token , expires_in ):
88+ def __init__ (self , access_token , account_id , user_id , url_state , refresh_token ,
89+ expires_in , scope ):
8190 """
8291 Same as OAuth2FlowNoRedirectResult but with url_state.
8392
@@ -86,20 +95,23 @@ def __init__(self, access_token, account_id, user_id, url_state, refresh_token,
8695 :meth:`DropboxOAuth2Flow.start`.
8796 """
8897 super (OAuth2FlowResult , self ).__init__ (
89- access_token , account_id , user_id , refresh_token , expires_in )
98+ access_token , account_id , user_id , refresh_token , expires_in , scope )
9099 self .url_state = url_state
91100
92101 @classmethod
93102 def from_no_redirect_result (cls , result , url_state ):
94103 assert isinstance (result , OAuth2FlowNoRedirectResult )
95104 return cls (result .access_token , result .account_id , result .user_id ,
96- url_state , result .refresh_token , result .expires_at )
105+ url_state , result .refresh_token , result .expires_at , result . scope )
97106
98107 def __repr__ (self ):
99- return 'OAuth2FlowResult(%s, %s, %s, %s, %s, %s)' % (
108+ return 'OAuth2FlowResult(%s, %s, %s, %s, %s, %s, %s, %s, %s )' % (
100109 self .access_token ,
110+ self .refresh_token ,
111+ self .expires_at ,
101112 self .account_id ,
102113 self .user_id ,
114+ self .scope ,
103115 self .url_state ,
104116 self .refresh_token ,
105117 self .expires_at ,
@@ -108,14 +120,22 @@ def __repr__(self):
108120
109121class DropboxOAuth2FlowBase (object ):
110122
111- def __init__ (self , consumer_key , consumer_secret , locale = None , token_access_type = 'legacy' ):
123+ def __init__ (self , consumer_key , consumer_secret , locale = None , token_access_type = 'legacy' ,
124+ scope = None , include_granted_scopes = None ):
125+ if scope is not None :
126+ assert len (scope ) > 0 and isinstance (scope , list ), \
127+ "Scope list must be of type list"
128+
112129 self .consumer_key = consumer_key
113130 self .consumer_secret = consumer_secret
114131 self .locale = locale
115132 self .token_access_type = token_access_type
116133 self .requests_session = pinned_session ()
134+ self .scope = scope
135+ self .include_granted_scopes = include_granted_scopes
117136
118- def _get_authorize_url (self , redirect_uri , state , token_access_type ):
137+ def _get_authorize_url (self , redirect_uri , state , token_access_type , scope = None ,
138+ include_granted_scopes = None ):
119139 params = dict (response_type = 'code' ,
120140 client_id = self .consumer_key )
121141 if redirect_uri is not None :
@@ -127,6 +147,12 @@ def _get_authorize_url(self, redirect_uri, state, token_access_type):
127147 if token_access_type != 'legacy' :
128148 params ['token_access_type' ] = token_access_type
129149
150+ if scope is not None :
151+ params ['scope' ] = " " .join (scope )
152+ if include_granted_scopes is not None :
153+ assert include_granted_scopes in INCLUDE_GRANTED_SCOPES_TYPES
154+ params ['include_granted_scopes' ] = str (include_granted_scopes )
155+
130156 return self .build_url ('/oauth2/authorize' , params , WEB_HOST )
131157
132158 def _finish (self , code , redirect_uri ):
@@ -163,6 +189,11 @@ def _finish(self, code, redirect_uri):
163189 else :
164190 expires_in = None
165191
192+ if 'scope' in d :
193+ scope = d ['scope' ]
194+ else :
195+ scope = None
196+
166197 uid = d ['uid' ]
167198
168199 return OAuth2FlowNoRedirectResult (
@@ -171,7 +202,7 @@ def _finish(self, code, redirect_uri):
171202 uid ,
172203 refresh_token ,
173204 expires_in ,
174- )
205+ scope )
175206
176207 def build_path (self , target , params = None ):
177208 """Build the path component for an API URL.
@@ -228,21 +259,23 @@ class DropboxOAuth2FlowNoRedirect(DropboxOAuth2FlowBase):
228259 auth_flow = DropboxOAuth2FlowNoRedirect(APP_KEY, APP_SECRET)
229260
230261 authorize_url = auth_flow.start()
231- print "1. Go to: " + authorize_url
232- print "2. Click \\ "Allow\\ " (you might have to log in first)."
233- print "3. Copy the authorization code."
262+ print( "1. Go to: " + authorize_url)
263+ print( "2. Click \\ "Allow\\ " (you might have to log in first).")
264+ print( "3. Copy the authorization code.")
234265 auth_code = raw_input("Enter the authorization code here: ").strip()
235266
236267 try:
237268 oauth_result = auth_flow.finish(auth_code)
238- except Exception, e:
269+ except Exception as e:
239270 print('Error: %s' % (e,))
240271 return
241272
242273 dbx = Dropbox(oauth_result.access_token)
243274 """
244275
245- def __init__ (self , consumer_key , consumer_secret , locale = None , token_access_type = 'legacy' ): # noqa: E501; pylint: disable=useless-super-delegation
276+ def __init__ (self , consumer_key , consumer_secret , locale = None , token_access_type = 'legacy' ,
277+ scope = None , include_granted_scopes = None ):
278+ # noqa: E501; pylint: disable=useless-super-delegation
246279 """
247280 Construct an instance.
248281
@@ -258,12 +291,21 @@ def __init__(self, consumer_key, consumer_secret, locale=None, token_access_type
258291 legacy - creates one long-lived token with no expiration
259292 online - create one short-lived token with an expiration
260293 offline - create one short-lived token with an expiration with a refresh token
294+ :param list scope: list of scopes to request in base oauth flow. If left blank,
295+ will default to all scopes for app
296+ :param str include_granted_scopes: which scopes to include from previous grants
297+ From the following enum:
298+ user - include user scopes in the grant
299+ team - include team scopes in the grant
300+ Note: if this user has never linked the app, include_granted_scopes must be None
261301 """
262302 super (DropboxOAuth2FlowNoRedirect , self ).__init__ (
263303 consumer_key ,
264304 consumer_secret ,
265305 locale ,
266306 token_access_type ,
307+ scope ,
308+ include_granted_scopes ,
267309 )
268310
269311 def start (self ):
@@ -275,7 +317,8 @@ def start(self):
275317 access the user's Dropbox account. Tell the user to visit this URL
276318 and approve your app.
277319 """
278- return self ._get_authorize_url (None , None , self .token_access_type )
320+ return self ._get_authorize_url (None , None , self .token_access_type , self .scope ,
321+ self .include_granted_scopes )
279322
280323 def finish (self , code ):
281324 """
@@ -337,7 +380,8 @@ def dropbox_auth_finish(web_app_session, request):
337380 """
338381
339382 def __init__ (self , consumer_key , consumer_secret , redirect_uri , session ,
340- csrf_token_session_key , locale = None , token_access_type = 'legacy' ):
383+ csrf_token_session_key , locale = None , token_access_type = 'legacy' ,
384+ scope = None , include_granted_scopes = None ):
341385 """
342386 Construct an instance.
343387
@@ -361,9 +405,17 @@ def __init__(self, consumer_key, consumer_secret, redirect_uri, session,
361405 legacy - creates one long-lived token with no expiration
362406 online - create one short-lived token with an expiration
363407 offline - create one short-lived token with an expiration with a refresh token
408+ :param list scope: list of scopes to request in base oauth flow. If left blank,
409+ will default to all scopes for app
410+ :param str include_granted_scopes: which scopes to include from previous grants
411+ From the following enum:
412+ user - include user scopes in the grant
413+ team - include team scopes in the grant
414+ Note: if this user has never linked the app, include_granted_scopes must be None
364415 """
365- super (DropboxOAuth2Flow , self ).__init__ (consumer_key , consumer_secret ,
366- locale , token_access_type )
416+ super (DropboxOAuth2Flow , self ).__init__ (consumer_key , consumer_secret , locale ,
417+ token_access_type , scope ,
418+ include_granted_scopes )
367419 self .redirect_uri = redirect_uri
368420 self .session = session
369421 self .csrf_token_session_key = csrf_token_session_key
@@ -397,7 +449,8 @@ def start(self, url_state=None):
397449 state += "|" + url_state
398450 self .session [self .csrf_token_session_key ] = csrf_token
399451
400- return self ._get_authorize_url (self .redirect_uri , state , self .token_access_type )
452+ return self ._get_authorize_url (self .redirect_uri , state , self .token_access_type ,
453+ self .scope , self .include_granted_scopes )
401454
402455 def finish (self , query_params ):
403456 """
0 commit comments