Skip to content

Commit 57de3e0

Browse files
author
Jon Wayne Parrott
authored
Add web sample for using google-auth for end-user auth (#1127)
* Add web sample for using google-auth for end-user auth Change-Id: I90856d5da694b9eab1b363f7982638482e10429a * Use apiclient Change-Id: Icb43629fa835682eeb0a248dbb56e12b15d0dd15 * Address review comments Change-Id: I3f7492601a6ec7f64dab611928dc1d6c5a23d9af * Fix missing redirect uri Change-Id: I98ea11e842c679caf944b134e745013962c5c34a * Fix some wording Change-Id: I44d4c690c8fb3702988cb303d4afc9872331bb32
1 parent a75e025 commit 57de3e0

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed

auth/end-user/web/main.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Copyright 2017 Google Inc. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""An example web application that obtains authorization and credentials from
16+
an end user.
17+
18+
This sample is used on
19+
https://developers.google.com/identity/protocols/OAuth2WebServer. Please
20+
refer to that page for instructions on using this sample.
21+
22+
Notably, you'll need to obtain a OAuth2.0 client secrets file and set the
23+
``GOOGLE_CLIENT_SECRETS`` environment variable to point to that file.
24+
"""
25+
26+
import os
27+
28+
import flask
29+
import google.oauth2.credentials
30+
import google_auth_oauthlib.flow
31+
import googleapiclient.discovery
32+
33+
# The path to the client-secrets.json file obtained from the Google API
34+
# Console. You must set this before running this application.
35+
CLIENT_SECRETS_FILENAME = os.environ['GOOGLE_CLIENT_SECRETS']
36+
# The OAuth 2.0 scopes that this application will ask the user for. In this
37+
# case the application will ask for basic profile information.
38+
SCOPES = ['email', 'profile']
39+
40+
app = flask.Flask(__name__)
41+
# TODO: A secret key is included in the sample so that it works but if you
42+
# use this code in your application please replace this with a truly secret
43+
# key. See http://flask.pocoo.org/docs/0.12/quickstart/#sessions.
44+
app.secret_key = 'TODO: replace with a secret value'
45+
46+
47+
@app.route('/')
48+
def index():
49+
if 'credentials' not in flask.session:
50+
return flask.redirect('authorize')
51+
52+
# Load the credentials from the session.
53+
credentials = google.oauth2.credentials.Credentials(
54+
**flask.session['credentials'])
55+
56+
# Get the basic user info from the Google OAuth2.0 API.
57+
client = googleapiclient.discovery.build(
58+
'oauth2', 'v2', credentials=credentials)
59+
60+
response = client.userinfo().v2().me().get().execute()
61+
62+
return str(response)
63+
64+
65+
@app.route('/authorize')
66+
def authorize():
67+
# Create a flow instance to manage the OAuth 2.0 Authorization Grant Flow
68+
# steps.
69+
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
70+
CLIENT_SECRETS_FILENAME, scopes=SCOPES)
71+
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)
72+
authorization_url, state = flow.authorization_url(
73+
# This parameter enables offline access which gives your application
74+
# an access token and a refresh token for the user's credentials.
75+
access_type='offline',
76+
# This parameter enables incremental auth.
77+
include_granted_scopes='true')
78+
79+
# Store the state in the session so that the callback can verify the
80+
# authorization server response.
81+
flask.session['state'] = state
82+
83+
return flask.redirect(authorization_url)
84+
85+
86+
@app.route('/oauth2callback')
87+
def oauth2callback():
88+
# Specify the state when creating the flow in the callback so that it can
89+
# verify the authorization server response.
90+
state = flask.session['state']
91+
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
92+
CLIENT_SECRETS_FILENAME, scopes=SCOPES, state=state)
93+
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)
94+
95+
# Use the authorization server's response to fetch the OAuth 2.0 tokens.
96+
authorization_response = flask.request.url
97+
flow.fetch_token(authorization_response=authorization_response)
98+
99+
# Store the credentials in the session.
100+
credentials = flow.credentials
101+
flask.session['credentials'] = {
102+
'token': credentials.token,
103+
'refresh_token': credentials.refresh_token,
104+
'token_uri': credentials.token_uri,
105+
'client_id': credentials.client_id,
106+
'client_secret': credentials.client_secret,
107+
'scopes': credentials.scopes
108+
}
109+
110+
return flask.redirect(flask.url_for('index'))
111+
112+
113+
if __name__ == '__main__':
114+
# When running locally with Flask's development server this disables
115+
# OAuthlib's HTTPs verification. When running in production with a WSGI
116+
# server such as gunicorn this option will not be set and your application
117+
# *must* use HTTPS.
118+
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
119+
app.run('localhost', 8080, debug=True)

auth/end-user/web/main_test.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright 2017 Google Inc. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import pytest
16+
17+
import main
18+
19+
# Note: samples that do end-user auth are difficult to test in an automated
20+
# way. These tests are basic sanity checks.
21+
22+
23+
@pytest.fixture
24+
def client():
25+
main.app.testing = True
26+
return main.app.test_client()
27+
28+
29+
def test_index_wo_credentials(client):
30+
r = client.get('/')
31+
assert r.status_code == 302
32+
assert r.headers['location'].endswith('/authorize')
33+
34+
35+
def test_authorize(client):
36+
r = client.get('/authorize')
37+
assert r.status_code == 302
38+
assert r.headers['location'].startswith('https://accounts.google.com')

auth/end-user/web/requirements.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
google-auth==1.1.0
2+
google-auth-oauthlib==0.1.1
3+
google-auth-httplib2==0.0.2
4+
google-api-python-client==1.6.3
5+
flask==0.12.2
6+
requests==2.18.4

0 commit comments

Comments
 (0)