1414
1515import os
1616import flask
17- from oauth2client import client
1817import requests
1918import json
2019import flask_sqlalchemy
@@ -67,14 +66,13 @@ class User(db.Model):
6766 email = db .Column (db .String (120 ), unique = True )
6867 portrait_url = db .Column (db .Text ())
6968
70- # The user's credentials .
71- # Note that refresh and access tokens will become invalid if:
69+ # The user's refresh token, which will be used to obtain an access token .
70+ # Note that refresh tokens will become invalid if:
7271 # - The refresh token has not been used for six months.
7372 # - The user revokes your app's access permissions.
7473 # - The user changes passwords.
7574 # - The user belongs to a Google Cloud Platform organization
7675 # that has session control policies in effect.
77- access_token = db .Column (db .Text ())
7876 refresh_token = db .Column (db .Text ())
7977
8078 def __repr__ (self ):
@@ -119,46 +117,59 @@ def classroom_addon():
119117 db .create_all ()
120118
121119 # Retrieve the login_hint and hd query parameters.
120+ login_hint = flask .request .args .get ("login_hint" )
121+ hd = flask .request .args .get ("hd" )
122+
122123 # It's possible that we might return to this route later, in which case the
123124 # parameters will not be passed in. Instead, use the values cached in the session.
124- login_hint = flask .request .args .get ("login_hint" ) or flask .session .get (
125- "login_hint" )
126- hd = flask .request .args .get ("hd" ) or flask .session .get ("hd" )
127125
128- # Ensure that these parameters are cached in the session.
129- if login_hint :
130- flask .session ["login_hint" ] = login_hint
131- if hd :
126+ # If neither query parameter is available, use the values in the session.
127+ if login_hint is None and hd is None :
128+ login_hint = flask .session .get ("login_hint" )
129+ hd = flask .session .get ("hd" )
130+
131+ # If there's no login_hint query parameter, then check for hd.
132+ # Send the user to the sign in page.
133+ elif hd is not None :
132134 flask .session ["hd" ] = hd
135+ return start_auth_flow ()
136+
137+ # If the login_hint query parameter is available, we'll store it in the session.
138+ else :
139+ flask .session ["login_hint" ] = login_hint
133140
134- # If we received a login_hint, we'll use it to check if we have any stored
135- # credentials for this user.
136- if login_hint :
137- stored_credentials = get_credentials_from_storage (login_hint )
138-
139- # If we have stored credentials, store them in the session.
140- if stored_credentials :
141- # Load the client secrets file contents.
142- client_secrets_dict = json .load (
143- open (CLIENT_SECRETS_FILE )).get ("web" )
144-
145- # Set the credentials in the session.
146- flask .session ["credentials" ] = {
147- "token" : stored_credentials .access_token ,
148- "refresh_token" : stored_credentials .refresh_token ,
149- "token_uri" : client_secrets_dict ["token_uri" ],
150- "client_id" : client_secrets_dict ["client_id" ],
151- "client_secret" : client_secrets_dict ["client_secret" ],
152- "scopes" : SCOPES
153- }
154-
155- # Set the username in the session.
156- flask .session ["username" ] = stored_credentials .display_name
157-
158- # Redirect to the authorization page if we received hd OR if we received
159- # login_hint but don't have any stored credentials for this user.
160- if "credentials" not in flask .session or hd :
161- return flask .render_template ("authorization.html" )
141+ # Check if we have any stored credentials for this user.
142+ stored_credentials = get_credentials_from_storage (login_hint )
143+
144+ # If we have stored credentials, load them into the session.
145+ if stored_credentials :
146+ # Load the client secrets file contents.
147+ client_secrets_dict = json .load (open (CLIENT_SECRETS_FILE )).get ("web" )
148+
149+ # Update the credentials in the session.
150+ if not flask .session .get ("credentials" ):
151+ flask .session ["credentials" ] = {}
152+
153+ flask .session ["credentials" ]["token" ] = flask .session .get ("credentials" ).get ("token" ) or None
154+ flask .session ["credentials" ][
155+ "refresh_token" ] = stored_credentials .refresh_token
156+ flask .session ["credentials" ]["token_uri" ] = client_secrets_dict [
157+ "token_uri" ]
158+ flask .session ["credentials" ]["client_id" ] = client_secrets_dict [
159+ "client_id" ]
160+ flask .session ["credentials" ]["client_secret" ] = client_secrets_dict [
161+ "client_secret" ]
162+ flask .session ["credentials" ]["scopes" ] = SCOPES
163+
164+ # Set the username in the session.
165+ flask .session ["username" ] = stored_credentials .display_name
166+
167+ # Redirect to the authorization page if we received login_hint but don't
168+ # have any stored credentials for this user. We need the refresh token
169+ # specifically.
170+ if "credentials" not in flask .session or \
171+ flask .session ["credentials" ]["refresh_token" ] is None :
172+ return start_auth_flow ()
162173
163174 return flask .render_template (
164175 "addon-discovery.html" ,
@@ -175,7 +186,7 @@ def test_api_request(request_type="username"):
175186 """
176187
177188 if "credentials" not in flask .session :
178- return flask . render_template ( "authorization.html" )
189+ return start_auth_flow ( )
179190
180191 # Load credentials from the session and client id and client secret from file.
181192 credentials = google .oauth2 .credentials .Credentials (
@@ -185,12 +196,12 @@ def test_api_request(request_type="username"):
185196 fetched_data = ""
186197
187198 if request_type == "username" :
188- if not flask .session .get ("username" ):
189- user_info_service = googleapiclient .discovery .build (
190- serviceName = "oauth2" , version = "v2" , credentials = credentials )
199+ # if not flask.session.get("username"):
200+ user_info_service = googleapiclient .discovery .build (
201+ serviceName = "oauth2" , version = "v2" , credentials = credentials )
191202
192- flask .session ["username" ] = (
193- user_info_service .userinfo ().get ().execute ().get ("name" ))
203+ flask .session ["username" ] = (
204+ user_info_service .userinfo ().get ().execute ().get ("name" ))
194205
195206 fetched_data = flask .session .get ("username" )
196207
@@ -308,10 +319,21 @@ def revoke():
308319
309320 status_code = getattr (revoke , "status_code" )
310321 if status_code == 200 :
311- return flask . render_template ( "authorization.html" )
322+ return start_auth_flow ( )
312323 else :
313324 return flask .render_template (
314- "index.html" , message = "An error occurred during revocation!" )
325+ "addon-discovery.html" ,
326+ message = "An error occurred during revocation!" )
327+
328+
329+ @app .route ("/start-auth-flow" )
330+ def start_auth_flow ():
331+ """
332+ Starts the OAuth 2.0 authorization flow. It's important that the
333+ template be rendered to properly manage popups.
334+ """
335+
336+ return flask .render_template ("authorization.html" )
315337
316338
317339@app .route ("/clear" )
@@ -377,16 +399,14 @@ def save_user_credentials(credentials=None, user_info=None):
377399 existing_user .email = user_info .get ("email" )
378400 existing_user .portrait_url = user_info .get ("picture" )
379401
380- if credentials :
381- existing_user .access_token = credentials .token
402+ if credentials and credentials .refresh_token is not None :
382403 existing_user .refresh_token = credentials .refresh_token
383404
384405 elif credentials and user_info :
385406 new_user = User (id = user_info .get ("id" ),
386407 display_name = user_info .get ("name" ),
387408 email = user_info .get ("email" ),
388409 portrait_url = user_info .get ("picture" ),
389- access_token = credentials .token ,
390410 refresh_token = credentials .refresh_token )
391411
392412 db .session .add (new_user )
0 commit comments