Configuration¶
All configuration is managed through FullAuthConfig, a Pydantic Settings class. Every option can be set via environment variables with the FULLAUTH_ prefix.
Usage¶
Pass config inline or as an object:
Reading from a .env file¶
FullAuthConfig reads a .env file in the current working directory by default (via pydantic-settings). Drop a .env next to your app entry point:
# .env
FULLAUTH_SECRET_KEY=replace-me-with-32-random-bytes
FULLAUTH_ACCESS_TOKEN_EXPIRE_MINUTES=15
FULLAUTH_BLACKLIST_BACKEND=redis
FULLAUTH_REDIS_URL=redis://localhost:6379/0
Then FullAuthConfig() picks it up = no extra wiring needed.
Precedence¶
pydantic-settings resolves values in this order, first wins:
- Init kwargs =
FullAuthConfig(SECRET_KEY="...") - Process environment =
os.environ["FULLAUTH_SECRET_KEY"] .envfile- Field defaults
So anything you export in your shell, in uvicorn --env-file, or in Docker env_file: overrides the dotfile. The dotfile is only read if the variable isn't already in os.environ.
Using a different file¶
Pass _env_file at construction:
Or subclass once in your app:
from fastapi_fullauth import FullAuthConfig
from pydantic_settings import SettingsConfigDict
class AppFullAuthConfig(FullAuthConfig):
model_config = SettingsConfigDict(
env_prefix="FULLAUTH_",
case_sensitive=True,
env_file=".env.local",
extra="ignore",
)
Cloud / container deployments¶
You don't need to change anything. Managed platforms (FastAPI Cloud, Fly, Railway, Render), Docker, and Kubernetes inject config as real environment variables = those end up in os.environ inside the container. The .env default simply doesn't find a file to read and falls through to the process env. No overhead, no surprises.
If you want to be defensively explicit that no file is ever read, pass FullAuthConfig(_env_file=None) = but it's not required.
Reference¶
Core¶
| Option | Type | Default | Description |
|---|---|---|---|
SECRET_KEY |
str \| None |
None |
JWT signing key. Auto-generated in dev if not set. |
ALGORITHM |
str |
"HS256" |
JWT signing algorithm. |
Tokens¶
| Option | Type | Default | Description |
|---|---|---|---|
ACCESS_TOKEN_EXPIRE_MINUTES |
int |
30 |
Access token lifetime. |
REFRESH_TOKEN_EXPIRE_DAYS |
int |
30 |
Refresh token lifetime. |
REFRESH_TOKEN_ROTATION |
bool |
True |
Issue new refresh token on each refresh. |
JWT_LEEWAY_SECONDS |
int |
30 |
Tolerance (seconds) for clock drift between client and server when validating exp/iat. |
PASSWORD_RESET_EXPIRE_MINUTES |
int |
15 |
Password-reset token lifetime. Kept short = independent of ACCESS_TOKEN_EXPIRE_MINUTES. |
EMAIL_VERIFY_EXPIRE_MINUTES |
int |
1440 |
Email-verification token lifetime (24 h). |
Passwords¶
| Option | Type | Default | Description |
|---|---|---|---|
PASSWORD_HASH_ALGORITHM |
"argon2id" \| "bcrypt" |
"argon2id" |
Hashing algorithm. |
PASSWORD_MIN_LENGTH |
int |
8 |
Minimum password length. |
Login¶
| Option | Type | Default | Description |
|---|---|---|---|
LOGIN_FIELD |
str |
"email" |
Field used for login ("email", "username", etc.). |
LOCKOUT_ENABLED |
bool |
True |
Enable account lockout after failed login attempts. |
LOCKOUT_BACKEND |
"memory" \| "redis" |
"memory" |
Lockout storage backend. Use "redis" for multi-worker deployments. |
MAX_LOGIN_ATTEMPTS |
int |
5 |
Failed attempts before account lockout. |
LOCKOUT_DURATION_MINUTES |
int |
15 |
Lockout duration after max attempts. |
Rate Limiting¶
Per-route auth rate limits are baked into the routers. Global request-rate
middleware (RateLimitMiddleware) is opt-in = import it from
fastapi_fullauth.middleware and call app.add_middleware(...) yourself.
| Option | Type | Default | Description |
|---|---|---|---|
RATE_LIMIT_BACKEND |
"memory" \| "redis" |
"memory" |
Backend used by AuthRateLimiter and create_rate_limiter(). Use "redis" in production = "memory" is per-process, so the effective limit is multiplied by the worker count. |
TRUSTED_PROXY_HEADERS |
list[str] |
[] |
Headers to read real client IP from (e.g. ["X-Forwarded-For"]). |
AUTH_RATE_LIMIT_ENABLED |
bool |
True |
Enable per-route auth rate limits. |
AUTH_RATE_LIMIT_LOGIN |
int |
5 |
Max login attempts per window. |
AUTH_RATE_LIMIT_REGISTER |
int |
3 |
Max registrations per window. |
AUTH_RATE_LIMIT_PASSWORD_RESET |
int |
3 |
Max password reset requests per window. |
AUTH_RATE_LIMIT_PASSKEY_AUTH |
int |
10 |
Max passkey authenticate/begin requests per window. |
AUTH_RATE_LIMIT_WINDOW_SECONDS |
int |
60 |
Rate limit window in seconds. |
Redis¶
| Option | Type | Default | Description |
|---|---|---|---|
REDIS_URL |
str \| None |
None |
Redis connection URL. Required when using Redis backends. |
Token Blacklist¶
| Option | Type | Default | Description |
|---|---|---|---|
BLACKLIST_ENABLED |
bool |
True |
Check blacklist on token decode. |
BLACKLIST_BACKEND |
"memory" \| "redis" |
"memory" |
Blacklist storage backend. Use "redis" in production = "memory" is per-process, so a token revoked on one worker remains usable on others (logout won't actually revoke). |
Middleware¶
init_app() does not wire middleware automatically. Import what you need from
fastapi_fullauth.middleware (SecurityHeadersMiddleware, CSRFMiddleware,
RateLimitMiddleware) and app.add_middleware(...) it yourself.
| Option | Type | Default | Description |
|---|---|---|---|
CSRF_SECRET |
str \| None |
None |
CSRF signing secret. Pass config.CSRF_SECRET or config.SECRET_KEY to CSRFMiddleware (≥ 32 chars). |
Cookies¶
| Option | Type | Default | Description |
|---|---|---|---|
COOKIE_NAME |
str |
"fullauth_access" |
Access token cookie name. |
COOKIE_SECURE |
bool |
True |
Set Secure flag on cookies. |
COOKIE_HTTPONLY |
bool |
True |
Set HttpOnly flag on cookies. |
COOKIE_SAMESITE |
"lax" \| "strict" \| "none" |
"lax" |
SameSite cookie policy. |
COOKIE_DOMAIN |
str \| None |
None |
Cookie domain. |
OAuth¶
| Option | Type | Default | Description |
|---|---|---|---|
OAUTH_STATE_EXPIRE_SECONDS |
int |
300 |
OAuth state token TTL (5 min). |
OAUTH_AUTO_LINK_BY_EMAIL |
bool |
True |
Auto-link OAuth accounts to existing users by email. |
PREVENT_REGISTRATION_ENUMERATION |
bool |
False |
When True, /register always returns 202 + a generic message whether or not the email is already registered = an attacker can't use registration responses to probe the user table. Opt-in because the default 201 + user / 409 conflict behavior is simpler for client apps. |
Routing¶
| Option | Type | Default | Description |
|---|---|---|---|
API_PREFIX |
str |
"/api/v1" |
URL prefix for all routes. |
AUTH_ROUTER_PREFIX |
str |
"/auth" |
Auth router sub-prefix. |
ROUTER_TAGS |
list[str] |
["Auth"] |
OpenAPI tags for auth routes. |
Passwords¶
| Option | Type | Default | Description |
|---|---|---|---|
PREVENT_LOGIN_TIMING_ATTACKS |
bool |
False |
Run a dummy password hash on failed lookups to mask response time. Prevents email enumeration via timing. |
Global defaults¶
| Option | Type | Default | Description |
|---|---|---|---|
BACKEND |
str |
"memory" |
Default backend for all subsystems (blacklist, lockout, rate limit, challenge store). Individual *_BACKEND settings override this. |
ORIGINS |
list[str] |
[] |
Default origins list. Propagates to PASSKEY_ORIGINS if not explicitly set. |
Tip
Set FULLAUTH_BACKEND=redis and FULLAUTH_REDIS_URL=redis://... to switch all subsystems to Redis at once. You can still override individual backends (e.g. LOCKOUT_BACKEND=memory for local dev).
Passkeys¶
| Option | Type | Default | Description |
|---|---|---|---|
PASSKEY_ENABLED |
bool |
False |
Enable passkey (WebAuthn) routes. |
PASSKEY_RP_ID |
str \| None |
None |
Relying Party ID (your domain, e.g. "example.com"). |
PASSKEY_RP_NAME |
str \| None |
None |
Relying Party display name (e.g. "My App"). |
PASSKEY_ORIGINS |
list[str] |
[] |
Allowed origins (e.g. ["https://example.com", "https://m.example.com"]). |
PASSKEY_CHALLENGE_BACKEND |
"memory" \| "redis" |
"memory" |
Challenge store backend. Use "redis" in production = "memory" is per-process and breaks under uvicorn --workers N (begin and complete can land on different workers). |
PASSKEY_CHALLENGE_TTL |
int |
60 |
Challenge expiry in seconds. |
PASSKEY_REQUIRE_USER_VERIFICATION |
bool |
True |
Require user verification (PIN/biometric) on register and authenticate. Set False only if you need to allow silent authenticators. |
Production example¶
A realistic .env file for a production deployment:
# .env.production
FULLAUTH_SECRET_KEY=your-32-char-secret-generated-by-secrets-module
FULLAUTH_ALGORITHM=HS256
# Tokens
FULLAUTH_ACCESS_TOKEN_EXPIRE_MINUTES=15
FULLAUTH_REFRESH_TOKEN_EXPIRE_DAYS=7
# All protection subsystems use Redis
FULLAUTH_BACKEND=redis
FULLAUTH_REDIS_URL=redis://redis:6379/0
# Password hashing
FULLAUTH_PASSWORD_HASH_ALGORITHM=argon2id
FULLAUTH_PASSWORD_MIN_LENGTH=10
# Lockout
FULLAUTH_MAX_LOGIN_ATTEMPTS=5
FULLAUTH_LOCKOUT_DURATION_MINUTES=15
# Rate limiting
FULLAUTH_AUTH_RATE_LIMIT_LOGIN=10
FULLAUTH_AUTH_RATE_LIMIT_WINDOW_SECONDS=60
# Routing
FULLAUTH_API_PREFIX=/api/v1
# Proxy (if behind Nginx/Cloudflare)
FULLAUTH_TRUSTED_PROXY_HEADERS=["X-Forwarded-For"]