Self-contained FastAPI auth microservice — JWT, Google OAuth2+PKCE, API keys, Redis revocation
1.6K
Self-hosted FastAPI authentication service for Docker Compose.
fa-auth-m8 gives Python microservice stacks a ready-to-run authentication
issuer: email/password login, Google OAuth2 with PKCE, JWT access and refresh
tokens, Redis-backed revocation, API keys, RBAC, Prometheus metrics, and
production-oriented Docker Compose examples.
Consumer services validate JWTs locally with
fastapi-m8, which bundles
auth-sdk-m8. In stateful mode,
consumers check revocation through the auth service private API instead of
connecting to auth Redis directly.
git clone https://github.com/mano8/fa-auth-m8.git
cd fa-auth-m8/examples/docker_compose/quickstart_m8
cp auth.env.example auth.env
cp api.env.example api.env
# Replace every "changethis" value in auth.env and api.env, then:
bash init.sh
docker compose up --build
Open:
http://localhost:9000/user/health/http://localhost:9000/user/docshttp://localhost:9000/fastapi/docsThe compose stacks run both services: auth_user_service as the authentication
issuer and fastapi_full as a ready-to-use protected FastAPI consumer service.
On Windows, run init.sh from Git Bash or WSL.
HttpOnly cookie and rotated on every refreshHS256, RS256, or ES256stateless, hybrid, and statefulPRIVATE_API_CONSUMERSuser, admin, superuserfastapi_full and fastapi_minimalReady-to-run examples live under
examples/docker_compose/.
| Stack | Database | Signing | Token mode | Best for |
|---|---|---|---|---|
quickstart_m8 | MariaDB 12 | HS256 | stateful | Fast local start |
postgres_m8 | PostgreSQL 18 | HS256 | stateful | PostgreSQL projects |
rs256_m8 | MariaDB 12 | RS256 | hybrid | Asymmetric signing and JWKS |
metrics_m8 | PostgreSQL 18 | HS256 | stateful | Prometheus and Grafana |
hardened_m8 | PostgreSQL 18 | RS256 | stateful | Production-capable hardened deployment |
vault_dev_m8 | PostgreSQL 18 | RS256 | stateful | Learning Vault-based secret injection |
Production note: quickstart_m8, postgres_m8, rs256_m8, metrics_m8, and
vault_dev_m8 are development or learning templates. Use hardened_m8 with its
production overlay for an internet-facing deployment path.
This repository includes two consumer services that show how application APIs
use fa-auth-m8 without writing their own authentication layer.
| Example | What it shows | Use it when |
|---|---|---|
examples/fastapi_full | A full consumer service with fastapi-m8, DB session wiring, migrations, health checks, metrics, auth dependencies, lifespan cleanup, and protected routes | You want a practical starting point for a real microservice |
examples/fastapi_minimal | The smallest protected FastAPI app: settings, build_auth_deps, create_app, and one authenticated /hello/ route | You want to see the integration pattern in a few files |
Every Docker Compose stack includes fastapi_full behind Traefik at
/fastapi. After startup, open http://localhost:9000/fastapi/docs to try the
consumer API next to the auth API.
The minimal example is for copying the integration pattern into a new service:
from fastapi_m8 import AppLifecycle, create_app
from .core.deps import auth
app = create_app(
settings,
api_router,
service_name="example-minimal",
service_version="1.0.0",
lifecycle=AppLifecycle(auth_deps=auth),
)
| Mode | Redis for JWT validation | Revocation behavior | Best for |
|---|---|---|---|
stateless | No | No instant access-token revocation | Maximum scalability |
hybrid | Refresh tokens only | Refresh tokens revoked immediately | Balanced default for asymmetric demos |
stateful | Yes | Access and refresh tokens revoked immediately | Strongest session control |
Google OAuth requires Redis for PKCE exchange and is disabled in stateless
mode.
docker pull tepochtli/fa-auth-m8:1.0.0
docker pull tepochtli/fa-auth-m8:latest
Use a pinned semver tag such as 1.0.0 for production. Avoid latest in
long-lived deployments.
To use the published image in your own compose stack:
services:
auth_user_service:
image: tepochtli/fa-auth-m8:1.0.0
Install the consumer helper package:
pip install "fastapi-m8>=3.2.0,<4.0.0"
Minimal auth dependency setup:
from fastapi_m8 import AuthDeps, build_auth_deps
from .config import settings
auth: AuthDeps = build_auth_deps(settings)
CurrentUser = auth.CurrentUser
For RS256 or ES256 deployments, consumers can validate tokens through the auth service JWKS endpoint:
ACCESS_TOKEN_ALGORITHM=RS256
JWKS_URI=http://auth_user_service:8000/user/.well-known/jwks.json
JWKS_CACHE_TTL_SECONDS=300
For stateful mode, configure per-consumer private API credentials:
TOKEN_MODE=stateful
INTROSPECTION_URL=http://auth_user_service:8000/user/private/v1/jti-status
INTERNAL_CLIENT_ID=example-api
PRIVATE_API_SECRET=<the consumer secret configured in PRIVATE_API_CONSUMERS>
The auth service private API no longer accepts one global shared private-route
secret. Each consumer must be registered in PRIVATE_API_CONSUMERS with only the
scopes it needs.
All routes are served under API_PREFIX, which defaults to /user.
POST /login/access-tokenPOST /login/refresh-token/POST /login/logout/GET /.well-known/jwks.jsonGET /profile/get/me/PATCH /profile/update/me/POST /profile/api-keys/GET /profile/api-keys/verifyGET /users/GET /sessions/GET /health/GET /metricsPOST /private/users/POST /private/v1/jti-statusGET /private/v1/events/streamPOST /private/v1/service-tokenSee the full route table and environment reference in the repository README.
License: Apache-2.0 © Eli Serra
Content type
Image
Digest
sha256:acaa45b57…
Size
82.7 MB
Last updated
19 days ago
docker pull tepochtli/fa-auth-m8