Add Google Sign-In to your Flask app

Recently, I integrated SSO with Google Sign-In into a web application using the oauthlib library. While working on this project, I found plenty of resources on SSO and oauthlib separately, but struggled to find a tutorial that could guide me through the setup of Google Sign-In using oauthlib in a timely manner. Therefore, I’ve written this post to provide a quick guide for those who want to implement the Authorization Code flow for Google Sign-In in Flask applications.


Would you benefit from reading this post?

Please note that this post assumes a certain level of familiarity with the topic at hand. While I won’t be providing an introduction to the basics, I trust that those who are already knowledgeable in this area will find the content useful:

After completing this tutorial, it will be possible for you to integrate a Google sign-in page into your application. The resulting workflow would resemble the following gif
Google Sign-In to your app workflow


Implement Google sign-in:

To follow the steps in this section, you’ll need to have already generated a CLIENT_ID, CLIENT_SECRET, and redirect_uri, and have decided on the resource (in our case, email) that you’ll be requesting for your application. Once you have these details, implementing Google Sign-In in a Flask app is just a matter of two simple steps:

  1. Generate a Google Sign-In URI, route the users to this Sign-In page from your landing page
  2. Redirect the user to a success page after they have successfully logged in using their Google credentials
1. Generate a Google Sign-In URI, route the users to this Sign-In page from your landing page

Create a landing page like the above image with Google Sign-In URI using oauthlib, this login page will prompt the users to enter their Google username and password.

CLIENT_ID = os.environ['CLIENT_ID']
CLIENT_SECRET = os.environ['CLIENT_SECRET']
 
DATA = {
        'response_type':"code", # this tells the auth server that we are invoking authorization workflow
        'redirect_uri':"https://localhost:5000/home", # redirect URI https://console.developers.google.com/apis/credentials
        'scope': 'https://www.googleapis.com/auth/userinfo.email', # resource we are trying to access through Google API
        'client_id':CLIENT_ID, # client ID from https://console.developers.google.com/apis/credentials
        'prompt':'consent'} # adds a consent screen
 
URL_DICT = {
        'google_oauth' : 'https://accounts.google.com/o/oauth2/v2/auth', # Google OAuth URI
        'token_gen' : 'https://oauth2.googleapis.com/token', # URI to generate token to access Google API
        'get_user_info' : 'https://www.googleapis.com/oauth2/v3/userinfo' # URI to get the user info
        }
 
# Create a Sign in URI
CLIENT = oauth2.WebApplicationClient(CLIENT_ID)
REQ_URI = CLIENT.prepare_request_uri(
    uri=URL_DICT['google_oauth'],
    redirect_uri=DATA['redirect_uri'],
    scope=DATA['scope'],
    prompt=DATA['prompt'])

Lets create a Flask view function to land the users on the Sign-In page

@app.route('/')
def login():
    "Home"
    # redirect to the newly created Sign-In URI
    return redirect(REQ_URI)
2. Redirect to success page after successfully logging in using Google credentials

Lets create a home route function that implements a page like the above image that redirects to redirect_uri set when generating CLIENT_ID and CLIENT_SECRET

@app.route('/home')
def home():
    "Redirect after Google login & consent"
 
    # Get the code after authenticating from the URL
    code = request.args.get('code')
 
    # Generate URL to generate token
    token_url, headers, body = CLIENT.prepare_token_request(
            URL_DICT['token_gen'],
            authorisation_response=request.url,
            # request.base_url is same as DATA['redirect_uri']
            redirect_url=request.base_url,
            code=code)
 
    # Generate token to access Google API
    token_response = requests.post(
            token_url,
            headers=headers,
            data=body,
            auth=(CLIENT_ID, CLIENT_SECRET))
 
    # Parse the token response
    CLIENT.parse_request_body_response(json.dumps(token_response.json()))
 
    # Add token to the  Google endpoint to get the user info
    # oauthlib uses the token parsed in the previous step
    uri, headers, body = CLIENT.add_token(URL_DICT['get_user_info'])
 
    # Get the user info
    response_user_info = requests.get(uri, headers=headers, data=body)
    info = response_user_info.json()
 
    return redirect('/user/%s' % info['email'])

Lets create a login_success function to redirect the user to a dynamic page with the user’s email

@app.route('/user/<email>')
def login_success(email):
    "Landing page after successful login"
 
    return "Hello %s" % email
Putting it all together
#!/usr/bin/env python3
"""
A Flask app for Google SSO
"""
 
import json
import os
import requests
from flask import Flask, redirect, request
from  oauthlib import oauth2
 
CLIENT_ID = os.environ['CLIENT_ID']
CLIENT_SECRET = os.environ['CLIENT_SECRET']
 
DATA = {
        'response_type':"code", # this tells the auth server that we are invoking authorization workflow
        'redirect_uri':"https://localhost:5000/home", # redirect URI https://console.developers.google.com/apis/credentials
        'scope': 'https://www.googleapis.com/auth/userinfo.email', # resource we are trying to access through Google API
        'client_id':CLIENT_ID, # client ID from https://console.developers.google.com/apis/credentials
        'prompt':'consent'} # adds a consent screen
 
URL_DICT = {
        'google_oauth' : 'https://accounts.google.com/o/oauth2/v2/auth', # Google OAuth URI
        'token_gen' : 'https://oauth2.googleapis.com/token', # URI to generate token to access Google API
        'get_user_info' : 'https://www.googleapis.com/oauth2/v3/userinfo' # URI to get the user info
        }
 
# Create a Sign in URI
CLIENT = oauth2.WebApplicationClient(CLIENT_ID)
REQ_URI = CLIENT.prepare_request_uri(
    uri=URL_DICT['google_oauth'],
    redirect_uri=DATA['redirect_uri'],
    scope=DATA['scope'],
    prompt=DATA['prompt'])
 
app = Flask(__name__)
 
@app.route('/')
def login():
    "Home"
    # redirect to the newly created Sign-In URI
    return redirect(REQ_URI)
 
@app.route('/home')
def home():
    "Redirect after Google login & consent"
 
    # Get the code after authenticating from the URL
    code = request.args.get('code')
 
    # Generate URL to generate token
    token_url, headers, body = CLIENT.prepare_token_request(
            URL_DICT['token_gen'],
            authorisation_response=request.url,
            # request.base_url is same as DATA['redirect_uri']
            redirect_url=request.base_url,
            code=code)
 
    # Generate token to access Google API
    token_response = requests.post(
            token_url,
            headers=headers,
            data=body,
            auth=(CLIENT_ID, CLIENT_SECRET))
 
    # Parse the token response
    CLIENT.parse_request_body_response(json.dumps(token_response.json()))
 
    # Add token to the  Google endpoint to get the user info
    # oauthlib uses the token parsed in the previous step
    uri, headers, body = CLIENT.add_token(URL_DICT['get_user_info'])
 
    # Get the user info
    response_user_info = requests.get(uri, headers=headers, data=body)
    info = response_user_info.json()
 
    return redirect('/user/%s' % info['email'])
 
@app.route('/user/<email>')
def login_success(email):
    "Landing page after successful login"
 
    return "Hello %s" % email
 
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000, ssl_context='adhoc')

To view this project on GitHub, simply follow this link: sso_google_oauthlib

That’s it! With this tutorial, you can easily integrate a Google Sign-In page into your Flask application


Hire Qxf2 for your testing needs

Modern stacks need modern testing. Contact Qxf2 to work with expert technical testers. Our testers go well beyond traditional test automation. We can help your teams test infrastructure maintained as code, add several types of tests to your data pipelines, integrate deep testing into your MLOPs cycle and so much more!


5 thoughts on “Add Google Sign-In to your Flask app

    1. Hi,
      I am reading there could be a lot of reasons why ERR_SSL_PROTOCOL_ERROR is triggered. Can you please share more info on the error:
      – Did you try using a different browser and do you see the same error?
      – Do you have the `ssl_context='adhoc' param set when calling app.run method?

Leave a Reply

Your email address will not be published. Required fields are marked *