Recently I was exploring the FastApi micro-framework of Python. There are many interesting features that are found in FastApi. While I was exploring FastApi in one of my projects, I was trying to integrate Google Oauth in my project.

Fast API is a modern, open-source, fast, and highly performant Python web framework used for building Web APIs and is based on Python 3.6+ standard type hints.

I don’t find much documentation on Google Oauth2 login docs compared with other frameworks. So I decided to share my experience here.

FastApi setup

from typing import Optional
from fastapi import FastAPI, Request

The Optional and FastAPI imports are standard among FastAPI applications. Optional is for type support in python. It is used for validating a user’s request before entering Api.

@app.get('/')
async def home(request: Request):
    user = request.session.get('user')
    if user is not None:
        return {id: user.id}
    return {"error": "Un-authorized"}

Implementing Google Auth in FastAPi

FastApi is created on top of Starlette. A FastAPI app is basically a Starlette app, that is why you can just use Authlib Starlette integration to create OAuth clients for FastAPI.

from authlib.integrations.starlette_client import OAuth
from starlette.config import Config

config = Config('.env')  # read config from .env file
oauth = OAuth(config)
oauth.register(
    name='google',
    server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
    client_kwargs={
        'scope': 'openid email profile'
    }
)

Above code reads client_secret and client_id from configuration file. If you want to do it manually via code, please refer to the code.

oauth.register(
    'google',
    client_id='...',
    client_secret='...',
    ...
)

Above are a few ways to pass client_id and client_secret. Instead I would prefer to read secrets from the environment file instead.

from starlette.config import environ
oauth.register(
    'google',
    client_id=environ['CLIENT_ID'],
    client_secret=environ['CLIENT_SECRET'],
    ...
)

Final code for initializing O-auth

from authlib.integrations.starlette_client import OAuth
from starlette.config import environ
oauth = OAuth()
oauth.register(
    name='google',
    server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
    client_id=environ['CLIENT_ID'],
    client_secret=environ['CLIENT_SECRET'],
    client_kwargs={
        'scope': 'user:email'
    }
)

However, unlike Flask/Django, Starlette OAuth registry is using HTTPX, So as part of this setup, please make sure httpx is installed

httpx is a fast and multi-purpose HTTP toolkit to run multiple probers using retryablehttp library, it is designed to maintain the result reliability with increased threads.

pip install httpx

Creating routes for Google login and Google callback url

@app.route('/login/google')
async def login_via_google(request):
    google = oauth.create_client('google')
    redirect_uri = request.url_for('authorize_google')
    return await google.authorize_redirect(request, redirect_uri)

@app.route('/auth/google')
async def authorize_google(request):
    google = oauth.create_client('google')
    token = await google.authorize_access_token(request)
    user = await google.parse_id_token(request, token)
    print(user)
    #set session or do something with the token and profile
    return {}

Using OAuth 2.0 to Access Google APIs

Go to google API console, Fetch credentials and save it in your project.

References:

  1. Authlib
  2. Authlib blog