Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mattbutton committed Feb 21, 2019
0 parents commit 5a44254
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 0 deletions.
131 changes: 131 additions & 0 deletions .gitignore
@@ -0,0 +1,131 @@
run.bat

# See https://help.github.com/ignore-files/ for more about ignoring files.

# dependencies
/node_modules

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*


# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/

.vscode
1 change: 1 addition & 0 deletions README.md
@@ -0,0 +1 @@
https://www.mattbutton.com/2019/01/05/google-authentication-with-python-and-flask/
94 changes: 94 additions & 0 deletions google_auth.py
@@ -0,0 +1,94 @@
import functools
import os

import flask

from authlib.client import OAuth2Session
import google.oauth2.credentials
import googleapiclient.discovery

ACCESS_TOKEN_URI = 'https://www.googleapis.com/oauth2/v4/token'
AUTHORIZATION_URL = 'https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&prompt=consent'

AUTHORIZATION_SCOPE ='openid email profile'

AUTH_REDIRECT_URI = os.environ.get("FN_AUTH_REDIRECT_URI", default=False)
BASE_URI = os.environ.get("FN_BASE_URI", default=False)
CLIENT_ID = os.environ.get("FN_CLIENT_ID", default=False)
CLIENT_SECRET = os.environ.get("FN_CLIENT_SECRET", default=False)

AUTH_TOKEN_KEY = 'auth_token'
AUTH_STATE_KEY = 'auth_state'
USER_INFO_KEY = 'user_info'

app = flask.Flask(__name__)
app.secret_key = os.environ.get("FN_FLASK_SECRET_KEY", default=False)

@app.route('/')
def index():
if is_logged_in():
user_info = get_user_info()
return 'You are currently logged in as ' + user_info['given_name']

return 'You are not currently logged in'

def no_cache(view):
@functools.wraps(view)
def no_cache_impl(*args, **kwargs):
response = flask.make_response(view(*args, **kwargs))
response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
response.headers['Pragma'] = 'no-cache'
response.headers['Expires'] = '-1'
return response

return functools.update_wrapper(no_cache_impl, view)

@app.route('/google/login')
@no_cache
def login():
session = OAuth2Session(CLIENT_ID, CLIENT_SECRET, scope=AUTHORIZATION_SCOPE, redirect_uri=AUTH_REDIRECT_URI)
uri, state = session.authorization_url(AUTHORIZATION_URL)
flask.session[AUTH_STATE_KEY] = state
flask.session.permanent = True
return flask.redirect(uri, code=302)


@app.route('/google/auth')
@no_cache
def google_auth_redirect():
state = flask.request.args.get('state', default=None, type=None)

session = OAuth2Session(CLIENT_ID, CLIENT_SECRET, scope=AUTHORIZATION_SCOPE, state=state, redirect_uri=AUTH_REDIRECT_URI)
oauth2_tokens = session.fetch_access_token(ACCESS_TOKEN_URI, authorization_response=flask.request.url)
flask.session[AUTH_TOKEN_KEY] = oauth2_tokens

return flask.redirect(BASE_URI, code=302)

@app.route('/google/logout')
@no_cache
def logout():
flask.session.pop(AUTH_TOKEN_KEY, None)
flask.session.pop(AUTH_STATE_KEY, None)
flask.session.pop(USER_INFO_KEY, None)

return flask.redirect(BASE_URI, code=302)

def is_logged_in():
return True if AUTH_TOKEN_KEY in flask.session else False

def build_credentials():
if not is_logged_in():
raise Exception('User must be logged in')

oauth2_tokens = flask.session[AUTH_TOKEN_KEY]
return google.oauth2.credentials.Credentials(
oauth2_tokens['access_token'],
refresh_token=oauth2_tokens['refresh_token'],
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
token_uri=ACCESS_TOKEN_URI)

def get_user_info():
credentials = build_credentials()
oauth2_client = googleapiclient.discovery.build('oauth2', 'v2', credentials=credentials)
return oauth2_client.userinfo().get().execute()
5 changes: 5 additions & 0 deletions requirements.txt
@@ -0,0 +1,5 @@
authlib==0.10
flask==1.0.2
google-api-python-client
google-auth
virtualenv
10 changes: 10 additions & 0 deletions run.bat.sample
@@ -0,0 +1,10 @@
set FN_AUTH_REDIRECT_URI=http://localhost:8040/google/auth
set FN_BASE_URI=http://localhost:8040
set FN_CLIENT_ID=THE CLIENT ID WHICH YOU CREATED EARLIER
set FN_CLIENT_SECRET=THE CLIENT SECRET WHICH YOU CREATED EARLIER

set FLASK_APP=google_auth.py
set FLASK_DEBUG=1
set FN_FLASK_SECRET_KEY=1234567

python -m flask run -p 8040

0 comments on commit 5a44254

Please sign in to comment.