Letting users sign in with their Google accounts can make your FastAPI app easier to use and more secure. Here's a clear, step-by-step guide to set it up.
Before jumping in, make sure you have:
pip install httpx
First, you need to configure things in the Google Developer Console.
Go to "OAuth consent screen" in the sidebar.
Navigate to "Credentials".
Click "Create credentials" and pick "OAuth client ID".
Select "Web application".
Enter your app's name.
For "Authorized JavaScript origins"
, use your app's origin, like https://localhost:5000
.
For "Authorized redirect URIs", add your callback URL, like https://localhost:5000/app/auth/google/callback
.
Click "Create" and copy your Client ID and Client Secret.
Note: The redirect URI in your code must match this exactly, or it won't work.
Now, let's write the code to handle Google sign-ins in your FastAPI app.
You'll need these variables:
https://localhost:5000
.Set them in a .env file or your environment. For a .env file, it'd look like:
GOOGLE_CLIENT_ID=your_client_id GOOGLE_CLIENT_SECRET=your_client_secret HOST=https://localhost:5000
Here's the FastAPI code to handle the login and callback:
from fastapi import APIRouter, HTTPException, Request, status from fastapi.responses import RedirectResponse import httpx router = APIRouter(prefix="/app") # Replace these with your actual values or load from environment GOOGLE_CLIENT_ID = "your_client_id" GOOGLE_CLIENT_SECRET = "your_client_secret" HOST = "https://localhost:5000" GOOGLE_REDIRECT_URI = f"{HOST}/app/auth/google/callback" GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/auth" GOOGLE_TOKEN_URL = "https://accounts.google.com/o/oauth2/token" GOOGLE_USER_INFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo" GOOGLE_SCOPE = "email" @router.get("/auth/google/login", include_in_schema=False, response_class=RedirectResponse) async def login_google(): """Redirect the user to Google's login page.""" google_oauth_url = ( f"{GOOGLE_AUTH_URL}?response_type=code&client_id={GOOGLE_CLIENT_ID}" f"&redirect_uri={GOOGLE_REDIRECT_URI}&scope={GOOGLE_SCOPE}&access_type=offline" ) return RedirectResponse(google_oauth_url, status_code=status.HTTP_302_FOUND) @router.get("/auth/google/callback", include_in_schema=False) async def auth_google(request: Request): """Handle the callback from Google after login.""" code = request.query_params.get("code") if not code: raise HTTPException(status_code=400, detail="No authorization code found") # Swap the code for an access token data = { "code": code, "client_id": GOOGLE_CLIENT_ID, "client_secret": GOOGLE_CLIENT_SECRET, "redirect_uri": GOOGLE_REDIRECT_URI, "grant_type": "authorization_code", } async with httpx.AsyncClient() as client: response = await client.post(GOOGLE_TOKEN_URL, data=data) response_data = response.json() access_token = response_data.get("access_token") if not access_token: raise HTTPException(status_code=400, detail="No access token received") # Get user info with the access token async with httpx.AsyncClient() as client: user_info_response = await client.get( GOOGLE_USER_INFO_URL, headers={"Authorization": f"Bearer {access_token}"} ) user_info = user_info_response.json() # Add your user handling logic here (e.g., create or log in user) return user_info # For now, just return the info
Login Route: Sends the user to Google's login page with your app's details.
Callback Route: Takes the code Google sends back, trades it for an access token, and uses that to grab the user's info (like their email).
Right now, the callback just returns the user info. You'll want to add logic to check if the user exists in your database. If not, create a new user with the Google ID and email. If they do exist, log them in. You could also set a cookie or token for session management.
Here's the flow after clicking "Sign in with Google":
Your query mentioned saving the Google ID in the database, which is a good idea. The code you provided does that, but I've simplified it here to focus on the basics. If you want to use the full version with IP tracking and custom models (like UserInfoResponse), you'll need to define those separately. For example, UserInfoResponse might look like:
from pydantic import BaseModel class UserInfoResponse(BaseModel): id: str email: str verified_email: bool picture: str
Also, your approach is solid, but I'd suggest adding a state parameter to the login URL to prevent CSRF attacks. Google supports it, and it's a simple security boost.
That's it! You've added Google Authentication to your FastAPI app. Users can sign in with their Google accounts, and you can use their info as needed. Test it out, and tweak it to fit your app - like adding more scopes or better error handling. Keep the access token secure, and you're good to go.
David Muraya is a Solutions Architect specializing in Python, FastAPI, and Cloud Infrastructure. He is passionate about building scalable, production-ready applications and sharing his knowledge with the developer community. You can connect with him on LinkedIn.
Enjoyed this blog post? Check out these related posts!
Full-Text Search: Using the Trigram Tokenizer Algorithm to Match Peoples Names
Leveraging Full Text Search and Trigram Tokenization for Efficient Name Matching
Read More..
Managing Background Tasks in FastAPI: BackgroundTasks vs ARQ + Redis
A practical guide to background processing in FastAPI, comparing built-in BackgroundTasks with ARQ and Redis for scalable async job queues.
Read More..
Adding Google Authentication to Your FastAPI Application
A guide to adding Google Authentication to your FastAPI app.
Read More..
Have a project in mind? Send me an email at hello@davidmuraya.com and let's bring your ideas to life. I am always available for exciting discussions.