© 2025 GitHub@programmingwithalex
FastAPI with Google Oauth2, JWT (access and refresh tokens), and Redis (refresh token storage and invalidation)
Lightweight authentication microservice built with Flask
frontend, FastAPI
auth service, JWT
access/refresh tokens, and Redis
-backed refresh tokens. Features Google OAuth2
login, secure token issuance, refresh-token rotation, and logout revocation.
This repository contains two components:
-
web_frontend (
Flask
):- Renders frontend templates (login, dashboard, settings)
- Delegates auth logic to auth_service
- Sets and clears session cookies
-
auth_service (
FastAPI
):- Google OAuth2 login: Exchange authorization codes for user info and issue tokens
- JWT access tokens: Stateless, short-lived (default 15 minutes)
- Opaque refresh tokens: Stored in Redis with single-use rotation (default 1 day TTL)
- Automatic token refresh: Clients can obtain new access/refresh pairs via
/token/refresh
- Logout revocation: Invalidate refresh tokens on logout to prevent reuse
- Configurable via:
.env
file or environment variables
Python
3.12+Docker
&Docker Compose
Redis
(can run locally or via Docker)
Create a .env
file in each service directory with the following keys:
auth_service (src/auth/.env
)¹
GOOGLE_OAUTH_TOKEN_URL="https://oauth2.googleapis.com/token"
GOOGLE_OAUTH_USERINFO_URL="https://www.googleapis.com/oauth2/v3/userinfo"
GOOGLE_OAUTH_CLIENT_ID=<your-google-client-id>
GOOGLE_OAUTH_CLIENT_SECRET=<your-google-client-secret>
SESSION_EXPIRE_TIME_SECONDS=3600
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_SSL=false # Set to true if using Redis with SSL
REDIS_PORT=6379
WEB_FRONTEND_URL="http://localhost:5000" # URL of the Auth service
JWT_SECRET_KEY="supersecret"
AUTH_SERVICE_URL=http://auth:8000 # corresponds to docker-compose.yml
SECRET_KEY=<your-flask-secret-key>
COOKIE_SECURE=false # Set to True in production with HTTPS
PORT_FLASK=5000
FLASK_ENV="development" # Set to "production" in production
At the project root, you can spin up the auth_service
, web_frontend
, and Redis
:
docker-compose up --build
web_service
available onhttp://localhost:5000
auth_service
available onhttp://localhost:8000
Redis
on port6379
-
GET
/login/google
Returns a Google OAuth2 authorization URL. -
GET
/auth/google?code=...
Callback for Google. Issues access & refresh tokens, then redirects to your front-end with both tokens. -
POST
/token/refresh
Request body:{ "refresh_token": "<token>" }
Response:{ "access_token": "...", "refresh_token": "...", "token_type": "bearer" }
-
POST
/verify
Header:Authorization: Bearer <access_token>
Response:{ "user": { "email": "...", "name": "..." } }
-
POST
/logout
Header:Authorization: Bearer <access_token>
Request body:{ "refresh_token": "<token>" }
Response:{ "message": "Logged out" }
Run at top-level directory.
python -m pytest -v
Use pre-commit hooks at the repo root:
pre-commit install
pre-commit run --all-files
Will also run on each commit to GitHub repo.
- JWT access token and refresh token TTL set differently between frontend and backend
- Set in two places:
FastAPI
auth service JWT token payloadexp
Flask
frontend web service Cookies
- Possible Issues:
Flask
frontend Cookie TTL longer the auth tokenexp
(Cookie outlives token)- Result:
- Browser will keep sending the cookie, but token already expired (or refresh key already vanished from Redis)
- Every request will 401 or every refresh attempt will fail—even though the cookie is still present
- Result:
Flask
frontend Cookie TTL shorter the auth tokenexp
(token outlives Cookie) 2. Result:- Browser silently drops cookie while token still technically valid on server side
- User’s POV → get logged out “too early,” because no cookie = no credentials, even though token not expired yet
- Possible solution:
- Set TTL values in single location (AWS
SSM Parameter Store
/AppConfig
)
- Set TTL values in single location (AWS
- Set in two places:
- implement on AWS using:
ECS
- single
Cluster
- two
Services
Flask
frontendFastAPI
auth service
- single
ElastiCache
- forRedis
clusterCDK
/Terraform
- IaCECS Service Connect
/API Gateway
- for communication between
ECS Services
ECS Service Connect
- communication ifServices
in sameAWS Cloud Map
- for communication between
API Gateway
- dedicated URL that can route to "auth service", which can be set in the "web front end"Service
- set
API Gateway
URL via:SSM Parameter Store
+ECS Task Definition
env varsAWS AppConfig
- set
- Have to setup on Google Cloud Console
- Create project to authenticate with OAuth2.0 on Google Cloud Console
- After creating project:
- Clients > Application Type > Web Application
- Authorized redirect URIs:
http://localhost:8000/auth/google
- Copy Google secret variables:
Client ID
Client secret