How it Works¶
FastAuth is a thin orchestration layer that connects providers, adapters, and transports together under a single FastAPI router.
Architecture overview¶
graph TD
APP["FastAPI Application"]
subgraph ROUTER["FastAuth Router /auth/*"]
ENDPOINTS["/register · /login · /logout · /refresh · /me
/oauth/{provider}/authorize · /oauth/{provider}/callback
/request-verify-email · /verify-email
/forgot-password · /reset-password
/account/* · /roles/* · /sessions/*"]
end
subgraph CORE["Core Logic"]
CORELOGIC["tokens · sessions · rbac · oauth · emails · jwks"]
end
subgraph PROVIDERS["Providers"]
direction LR
P1["Credentials"]
P2["Google"]
P3["GitHub"]
end
subgraph ADAPTERS["Adapters"]
direction LR
A1["SQLAlchemy"]
A2["Memory"]
A3["Custom"]
end
subgraph TRANSPORTS["Transports"]
direction LR
T1["SMTP"]
T2["Console"]
T3["Webhook"]
end
APP --> ROUTER
ROUTER --> CORE
CORE --> PROVIDERS & ADAPTERS & TRANSPORTS
Layers¶
| Layer | Responsibility |
|---|---|
| API (router) | HTTP endpoints — validates request bodies, calls core logic, returns responses |
| Core | Business logic — token creation, session management, RBAC checks |
| Providers | Authenticate users — verify a password or exchange an OAuth code |
| Adapters | Persist data — read/write users, tokens, sessions, roles in a database |
| Transports | Deliver emails — SMTP, webhook, or console (for dev) |
Sign-in flow (credentials)¶
The sequence below shows what happens when a user posts { email, password } to /auth/login:
sequenceDiagram
participant C as Client
participant FA as FastAuth Router
participant P as CredentialsProvider
participant A as UserAdapter
participant T as Core/Tokens
C->>FA: POST /auth/login {email, password}
FA->>P: authenticate({email, password})
P->>A: get_user_by_email(email)
A-->>P: user record (or None)
P->>P: verify_password(plain, hashed)
P-->>FA: user (or None)
alt authentication failed
FA-->>C: 401 Unauthorized
else success
FA->>FA: hooks.on_signin(user, "credentials")
FA->>T: create_access_token(user)
FA->>T: create_refresh_token(user)
T-->>FA: {access_token, refresh_token}
FA-->>C: 200 OK {access_token, refresh_token, token_type, expires_in}
end
Request authentication flow¶
When a protected route uses Depends(require_auth):
sequenceDiagram
participant C as Client
participant R as Protected Route
participant D as require_auth dep
participant T as Core/Tokens
participant A as UserAdapter
C->>R: GET /dashboard (Authorization: Bearer <token>)
R->>D: Depends(require_auth)
D->>D: extract token from header or cookie
D->>T: decode_token(token_str)
T-->>D: claims {sub, type, exp}
alt token invalid or expired
D-->>C: 401 Unauthorized
else
D->>A: get_user_by_id(claims["sub"])
A-->>D: user record
D-->>R: user
R-->>C: 200 OK {response data}
end
Key design decisions¶
Protocol-based (duck typing) — Every adapter and transport is defined as a Python Protocol. You never inherit from a FastAuth base class; you just implement the right methods and pass your object in.
Async-first — All adapters, providers, and hooks are async. FastAuth works natively with SQLAlchemy's async engine, aioredis, aiosmtplib, and httpx.
Opt-in features — Email flows, RBAC, OAuth, JWKS — nothing is enabled unless you configure it. A minimal install has zero runtime dependencies beyond cuid2 and pydantic.