Python Google Oauth2 Login Integration

Written by

in

Python Google OAuth2 login integration is one of the most requested features for modern web applications. By allowing users to sign in with their Google accounts, developers can boost conversion rates, reduce password fatigue, and leverage Google’s robust security infrastructure. In this guide we’ll walk through everything you need to know to implement a seamless Google OAuth2 login flow in a Python web app—covering setup in the Google Cloud Console, configuring Flask (or Django) back‑ends, handling tokens securely, and troubleshooting common pitfalls. Whether you’re building a small prototype or a production‑grade service, the step‑by‑step instructions below will get you up and running quickly.

Why Choose Google OAuth2 for Python Applications?

  • Trusted security: Google handles authentication, multi‑factor verification, and account recovery.
  • Reduced friction: Users can sign in with a single click, increasing signup completion rates.
  • Rich user profile data: Access to email, name, picture, and custom scopes for Google APIs.
  • Scalable and compliant: Built on OAuth 2.0 standards, meeting GDPR and CCPA requirements.

Prerequisites Before You Start

  1. A Google Cloud Platform (GCP) project with the OAuth consent screen configured.
  2. Python 3.8+ installed locally or on your server.
  3. A web framework such as Flask or Django. This tutorial uses Flask for simplicity.
  4. Basic knowledge of HTTP, redirects, and JSON handling.

Step 1: Create OAuth 2.0 Credentials in Google Cloud Console

1.1 Enable the Google Identity Services API

Navigate to the APIs & Services Library and enable Google Identity Services. This API provides the endpoints needed for token exchange and user info retrieval.

1.2 Configure the OAuth consent screen

Go to OAuth consent screen and fill in:

  • App name, support email, and developer contact information.
  • Scopes you intend to request (e.g., email, profile, openid).
  • Authorized domains (your production domain and any local development URLs like localhost).

1.3 Generate client ID and client secret

Under Credentials → Create Credentials → OAuth client ID, select Web application. Add the following Authorized redirect URIs (adjust the port if needed):

http://localhost:5000/auth/callback
https://yourdomain.com/auth/callback

Save the generated Client ID and Client Secret. You’ll need them in your Python code.

Step 2: Set Up the Python Environment

2.1 Install required packages

pip install Flask requests-oauthlib python-dotenv

The requests-oauthlib library simplifies the OAuth 2.0 flow, while python-dotenv helps keep secrets out of source control.

2.2 Create a .env file

GOOGLE_CLIENT_ID=YOUR_CLIENT_ID.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=YOUR_CLIENT_SECRET
SECRET_KEY=your_flask_secret_key

Load these variables in your Flask app using python-dotenv.

Step 3: Implement the OAuth Flow in Flask

3.1 Basic Flask app skeleton

from flask import Flask, redirect, url_for, session, request, jsonify
from requests_oauthlib import OAuth2Session
from dotenv import load_dotenv
import os

load_dotenv()
app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY')

# Google OAuth2 endpoints
AUTHORIZATION_BASE_URL = 'https://accounts.google.com/o/oauth2/v2/auth'
TOKEN_URL = 'https://oauth2.googleapis.com/token'
USER_INFO_URL = 'https://www.googleapis.com/oauth2/v3/userinfo'

# Scopes we need
SCOPE = ['openid', 'https://www.googleapis.com/auth/userinfo.email',
         'https://www.googleapis.com/auth/userinfo.profile']

3.2 Login route – redirect to Google

@app.route('/login')
def login():
    google = OAuth2Session(
        client_id=os.getenv('GOOGLE_CLIENT_ID'),
        scope=SCOPE,
        redirect_uri=url_for('callback', _external=True)
    )
    authorization_url, state = google.authorization_url(
        AUTHORIZATION_BASE_URL,
        access_type='offline',
        prompt='select_account'
    )
    # Store state in session to protect against CSRF
    session['oauth_state'] = state
    return redirect(authorization_url)

3.3 Callback route – exchange code for tokens

@app.route('/auth/callback')
def callback():
    google = OAuth2Session(
        client_id=os.getenv('GOOGLE_CLIENT_ID'),
        redirect_uri=url_for('callback', _external=True),
        state=session.get('oauth_state')
    )
    token = google.fetch_token(
        TOKEN_URL,
        client_secret=os.getenv('GOOGLE_CLIENT_SECRET'),
        authorization_response=request.url
    )
    # Save token securely (e.g., in a server‑side session or DB)
    session['oauth_token'] = token

    # Retrieve user profile
    resp = google.get(USER_INFO_URL)
    user_info = resp.json()
    # Example: store user info in session
    session['user'] = {
        'id': user_info['sub'],
        'email': user_info['email'],
        'name': user_info['name'],
        'picture': user_info['picture']
    }
    return redirect(url_for('profile'))

3.4 Protected profile page

@app.route('/profile')
def profile():
    user = session.get('user')
    if not user:
        return redirect(url_for('login'))
    return f"""
    

Welcome, {user['name']}!

Profile picture

Email: {user['email']}

Logout """

3.5 Logout route

@app.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('index'))

Step 4: Secure Token Management

  • Never expose the client secret to the browser. Keep it on the server side only.
  • Store access and refresh tokens in an encrypted database if you need long‑term access.
  • Validate the id_token signature using Google’s public keys (available at https://www.googleapis.com/oauth2/v3/certs) for added security.
  • Implement token refresh logic: when the access token expires, use the refresh token to obtain a new one without prompting the user again.

Step 5: Extending the Integration – Accessing Google APIs

Once you have a valid access token, you can call any Google API that matches the scopes you requested. For example, to list the authenticated user’s Google Drive files:

import requests

def list_drive_files():
    token = session.get('oauth_token')
    headers = {'Authorization': f"Bearer {token['access_token']}"}
    drive_api = 'https://www.googleapis.com/drive/v3/files'
    response = requests.get(drive_api, headers=headers, params={'pageSize': 10})
    return response.json()

Common Errors and How to Fix Them

Invalid redirect URI

Google will reject the request if the redirect_uri does not exactly match one of the URIs you entered in the Cloud Console. Double‑check for trailing slashes, HTTP vs. HTTPS, and port numbers.

CSRF state mismatch

If the state stored in the session differs from the one returned by Google, the callback will raise a InvalidStateError. Ensure you store session['oauth_state'] before the redirect and retrieve the same value in the callback.

Expired or revoked token

When an access token expires, Google returns a 401 Unauthorized. Use the stored refresh_token to request a new access token, or redirect the user to the login flow again if the refresh token is also invalid.

Testing Locally vs. Production

  • Local development: Use http://localhost:5000 as an authorized domain. Some browsers block third‑party cookies on localhost; consider using SameSite=None; Secure flags only in production.
  • Production: Enforce HTTPS, set SESSION_COOKIE_SECURE = True in Flask, and consider using a reverse proxy (e.g., Nginx) to terminate SSL.
  • Enable Google’s test users feature while the app is in “Testing” mode to avoid a public verification process.

Performance Tips for High‑Traffic Sites

  1. Cache the Google public keys for token verification (they rotate about once per hour).
  2. Store user sessions in a fast key‑value store like Redis instead of server memory.
  3. Limit the

Comments

Leave a Reply

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