· 6 years ago · Mar 23, 2020, 05:02 PM
1# -*- coding: utf-8 -*-
2
3import os
4import flask
5import requests
6
7import google.oauth2.credentials
8import google_auth_oauthlib.flow
9import googleapiclient.discovery
10
11# This variable specifies the name of a file that contains the OAuth 2.0
12# information for this application, including its client_id and client_secret.
13CLIENT_SECRETS_FILE = "client_secrets.json"
14
15
16SCOPES = "openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/analytics.readonly https://www.googleapis.com/auth/userinfo.email"
17API_SERVICE_NAME = 'analytics'
18API_VERSION = 'v3'
19
20app = flask.Flask(__name__)
21# Note: A secret key is included in the sample so that it works.
22# If you use this code in your application, replace this with a truly secret
23# key. See http://flask.pocoo.org/docs/0.12/quickstart/#sessions.
24app.secret_key = 'olajos9ASDkas-12lkajsdw'
25
26
27@app.route('/')
28def index():
29 return print_index_table()
30
31
32@app.route('/test')
33def test_api_request():
34 if 'credentials' not in flask.session:
35 return flask.redirect('authorize')
36
37 # Load credentials from the session.
38 credentials = google.oauth2.credentials.Credentials(
39 **flask.session['credentials'])
40
41 service = googleapiclient.discovery.build(
42 API_SERVICE_NAME, API_VERSION, credentials=credentials)
43
44 files = service.management().accounts().list().execute()
45
46 # Save credentials back to session in case access token was refreshed.
47 # ACTION ITEM: In a production app, you likely want to save these
48 # credentials in a persistent database instead.
49 flask.session['credentials'] = credentials_to_dict(credentials)
50 print(credentials_to_dict(credentials))
51 return flask.jsonify(**files)
52
53
54@app.route('/authorize')
55def authorize():
56 # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
57 flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
58 CLIENT_SECRETS_FILE, scopes=SCOPES)
59
60 flow.redirect_uri = flask.url_for('oauth2callback', _external=True)
61
62 authorization_url, state = flow.authorization_url(
63 # Enable offline access so that you can refresh an access token without
64 # re-prompting the user for permission. Recommended for web server apps.
65 access_type='offline',
66 # Enable incremental authorization. Recommended as a best practice.
67 include_granted_scopes='true')
68
69 # Store the state so the callback can verify the auth server response.
70 flask.session['state'] = state
71
72 return flask.redirect(authorization_url)
73
74
75@app.route('/oauth2callback')
76def oauth2callback():
77 # Specify the state when creating the flow in the callback so that it can
78 # verified in the authorization server response.
79 state = flask.session['state']
80
81 flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
82 CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
83 flow.redirect_uri = flask.url_for('oauth2callback', _external=True)
84
85 # Use the authorization server's response to fetch the OAuth 2.0 tokens.
86 authorization_response = flask.request.url
87 flow.fetch_token(authorization_response=authorization_response)
88
89 # Store credentials in the session.
90 # ACTION ITEM: In a production app, you likely want to save these
91 # credentials in a persistent database instead.
92 credentials = flow.credentials
93 import pdb; pdb.set_trace()
94
95 flask.session['credentials'] = credentials_to_dict(credentials)
96
97 return flask.redirect(flask.url_for('test_api_request'))
98
99
100@app.route('/revoke')
101def revoke():
102 if 'credentials' not in flask.session:
103 return ('You need to <a href="/authorize">authorize</a> before ' +
104 'testing the code to revoke credentials.')
105
106 credentials = google.oauth2.credentials.Credentials(
107 **flask.session['credentials'])
108
109 revoke = requests.post('https://accounts.google.com/o/oauth2/revoke',
110 params={'token': credentials.token},
111 headers = {'content-type': 'application/x-www-form-urlencoded'})
112
113 status_code = getattr(revoke, 'status_code')
114 if status_code == 200:
115 return('Credentials successfully revoked.' + print_index_table())
116 else:
117 return('An error occurred.' + print_index_table())
118
119
120@app.route('/clear')
121def clear_credentials():
122 if 'credentials' in flask.session:
123 del flask.session['credentials']
124 return ('Credentials have been cleared.<br><br>' +
125 print_index_table())
126
127
128def credentials_to_dict(credentials):
129 return {'token': credentials.token,
130 'refresh_token': credentials.refresh_token,
131 'token_uri': credentials.token_uri,
132 'client_id': credentials.client_id,
133 'client_secret': credentials.client_secret,
134 'scopes': credentials.scopes}
135
136def print_index_table():
137 return ('<table>' +
138 '<tr><td><a href="/test">Test an API request</a></td>' +
139 '<td>Submit an API request and see a formatted JSON response. ' +
140 ' Go through the authorization flow if there are no stored ' +
141 ' credentials for the user.</td></tr>' +
142 '<tr><td><a href="/authorize">Test the auth flow directly</a></td>' +
143 '<td>Go directly to the authorization flow. If there are stored ' +
144 ' credentials, you still might not be prompted to reauthorize ' +
145 ' the application.</td></tr>' +
146 '<tr><td><a href="/revoke">Revoke current credentials</a></td>' +
147 '<td>Revoke the access token associated with the current user ' +
148 ' session. After revoking credentials, if you go to the test ' +
149 ' page, you should see an <code>invalid_grant</code> error.' +
150 '</td></tr>' +
151 '<tr><td><a href="/clear">Clear Flask session credentials</a></td>' +
152 '<td>Clear the access token currently stored in the user session. ' +
153 ' After clearing the token, if you <a href="/test">test the ' +
154 ' API request</a> again, you should go back to the auth flow.' +
155 '</td></tr></table>')
156
157
158if __name__ == '__main__':
159 # When running locally, disable OAuthlib's HTTPs verification.
160 # ACTION ITEM for developers:
161 # When running in production *do not* leave this option enabled.
162 os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
163
164 # Specify a hostname and port that are set as a valid redirect URI
165 # for your API project in the Google API Console.
166 app.run('localhost', 8080, debug=True)