Security Architecture
Security is the foundation of any authentication framework. AllSafe Fast is designed with a defense-in-depth approach, addressing common authentication threats at multiple layers. This page documents the security architecture, the threats it mitigates, and how to configure each protection.
Threat → Mitigation → Configuration → Operational
The following table maps common authentication threats to AllSafe Fast's mitigations, the configuration that controls them, and operational practices you should follow:
| Threat | Mitigation | Configuration | Operational |
|---|---|---|---|
| Password cracking | Argon2id hashing with salt | Automatic, no config needed | Use strong password policies |
| Session theft | Token rotation, refresh token hashing, theft detection | ALLSAFE_REFRESH_TOKEN_EXPIRE |
Monitor for token reuse alerts |
| Token forgery | JWT signed with secret key, HS256 algorithm | ALLSAFE_SECRET_KEY, ALLSAFE_JWT_ALGORITHM |
Rotate secret keys periodically |
| Brute force attacks | Rate limiting (sliding window) | ALLSAFE_RATE_LIMIT, ALLSAFE_RATE_LIMIT_WINDOW |
Tune limits per endpoint sensitivity |
| CSRF attacks | SameSite cookies, token-based auth | ALLSAFE_COOKIE_SAME_SITE |
Verify SameSite is not none in production |
| Account enumeration | Generic error messages, timing-safe responses | Automatic | Use consistent error responses |
| Cookie theft (XSS) | HttpOnly, Secure cookies | ALLSAFE_COOKIE_HTTP_ONLY, ALLSAFE_COOKIE_SECURE |
Always use HTTPS in production |
| Default secret key | Production guard rejects default key | ALLSAFE_ENV=production |
Never deploy with default secret key |
| Insecure cookie transport | Production guard rejects cookie_secure=false |
ALLSAFE_ENV=production |
Ensure HTTPS termination is configured |
Password Security
AllSafe Fast uses Argon2id for password hashing. Argon2id is the winner of the Password Hashing Competition (PHC) and provides resistance against both GPU-based and side-channel attacks:
- Argon2id — A hybrid of Argon2i (side-channel resistant) and Argon2d (GPU resistant). The recommended choice for password hashing.
- Per-password salt — Each password hash uses a unique salt, preventing rainbow table attacks.
- Configurable parameters — Memory cost, time cost, and parallelism can be tuned for your hardware.
- Constant-time comparison — Password verification uses constant-time comparison to prevent timing attacks.
# Password hashing is handled automatically by AllSafe Fast
# When a user signs up with a password, it is hashed with Argon2id
# The hash is stored in allsafe_accounts.password_hash
user = await auth.create_user(
email="alice@example.com",
password="super-secure-password", # hashed before storage
)
# Verification uses constant-time comparison
await auth.sign_in_with_password(
email="alice@example.com",
password="super-secure-password", # verified against hash
)
Session Security
AllSafe Fast implements a robust session management system with multiple layers of protection:
Refresh Token Rotation
Each time a refresh token is used to obtain a new access token, the old refresh token is revoked and a new one is issued. This limits the window of opportunity for an attacker who steals a refresh token:
# Token rotation flow
# 1. User signs in -> receives access token + refresh token (RT1)
# 2. Access token expires -> client sends RT1 to refresh endpoint
# 3. Server validates RT1, revokes RT1, issues new access token + RT2
# 4. If RT1 is used again after RT2 is issued -> theft detected, all sessions revoked
Theft Detection
If a refresh token that has already been rotated is presented again, AllSafe Fast detects this as potential token theft and immediately revokes all of the user's sessions:
from allsafe_fast import TokenReuseError
# If a stolen refresh token is reused after rotation
try:
await auth.refresh_session(stolen_refresh_token)
except TokenReuseError:
# All user sessions have been revoked
# The legitimate user will need to sign in again
pass
Session Storage
Refresh tokens are stored as SHA-256 hashes in the allsafe_sessions table. This means even if the database is compromised, the attacker cannot use the stored hashes as valid refresh tokens.
Token Security
AllSafe Fast uses JSON Web Tokens (JWT) for access tokens. The following security measures apply:
- HS256 signing — Tokens are signed with HMAC-SHA256 using the secret key. This prevents tampering.
- SHA-256 hashing — Refresh tokens and verification tokens are stored as SHA-256 hashes, never in plaintext.
- Constant-time comparison — Token comparison uses constant-time algorithms to prevent timing attacks.
- Short-lived access tokens — Access tokens expire quickly (default: 900 seconds / 15 minutes) to limit damage from token theft.
- Issuer and audience claims — Tokens include
iss(issuer) andaud(audience) claims for validation.
| Token Type | Lifetime | Storage | Purpose |
|---|---|---|---|
| Access token (JWT) | 900s (15 min) | Client-side (cookie/header) | API authentication |
| Refresh token | 2592000s (30 days) | Hashed in database | Obtain new access tokens |
| Verification token | Configurable | Hashed in database | Email verification, password reset |
CSRF Protection
AllSafe Fast protects against Cross-Site Request Forgery (CSRF) through cookie attributes:
- SameSite cookies — By default, cookies are set with
SameSite=Lax, which prevents them from being sent in cross-site requests. This is the primary CSRF defense. - Token-based auth — Access tokens can be sent via the
Authorizationheader instead of cookies, which is inherently CSRF-resistant. - Configurable SameSite — You can set
SameSite=Strictfor maximum protection orSameSite=None(requiresSecure) for cross-site scenarios.
# Cookie security configuration
AuthConfig(
cookie_same_site="lax", # Default: lax (CSRF protection)
cookie_secure=True, # HTTPS only
cookie_http_only=True, # Not accessible via JavaScript
)
# Environment variable equivalents
# ALLSAFE_COOKIE_SAME_SITE=lax
# ALLSAFE_COOKIE_SECURE=true
# ALLSAFE_COOKIE_HTTP_ONLY=true
Account Enumeration Prevention
Account enumeration attacks try to determine whether an email address is registered by observing differences in the application's responses. AllSafe Fast prevents this by:
- Generic error messages — Sign-in failures return the same error message regardless of whether the email exists or the password is wrong.
- Consistent response timing — Password verification uses constant-time comparison, so the response time doesn't reveal whether the email exists.
- Generic verification responses — Password reset and email verification endpoints return generic success messages regardless of whether the email is registered.
# Sign-in always returns the same error for invalid credentials
# regardless of whether the email exists
await auth.sign_in_with_password(email, password)
# Error: "Invalid email or password" — same for both cases
# Password reset always returns success
await auth.request_password_reset(email)
# Always returns: "If the email is registered, a reset link has been sent"
Rate Limiting
AllSafe Fast includes built-in rate limiting to protect against brute force attacks. See the Rate Limiting page for full details.
- Sliding window algorithm — Tracks requests over a time window, not just a fixed counter.
- Redis backend — Atomic operations using sorted sets for distributed rate limiting.
- In-memory backend — For development and testing without Redis.
- Configurable limits —
ALLSAFE_RATE_LIMIT(default: 5) andALLSAFE_RATE_LIMIT_WINDOW(default: 900s).
Cookie Security
AllSafe Fast sets cookies with security-focused attributes by default:
document.cookie), preventing XSS-based token theft. Default: true.true. Must be true in production.lax (default) provides CSRF protection. Options: lax, strict, none.| Attribute | Default | Env Variable | Production Requirement |
|---|---|---|---|
| HttpOnly | true | ALLSAFE_COOKIE_HTTP_ONLY | Must be true |
| Secure | true | ALLSAFE_COOKIE_SECURE | Must be true |
| SameSite | lax | ALLSAFE_COOKIE_SAME_SITE | Must not be none without Secure |
Production Guards
AllSafe Fast includes built-in guards that prevent insecure production deployments. When ALLSAFE_ENV=production (or AuthConfig.is_production is True), the following checks are enforced:
If ALLSAFE_ENV=production and the secret key is still the default value ("change-me-please-..."), AllSafe Fast raises a ConfigurationError and refuses to start. You must set a unique, strong secret key.
If ALLSAFE_ENV=production and ALLSAFE_COOKIE_SECURE=false, AllSafe Fast raises a ConfigurationError. Cookies must be secure (HTTPS only) in production.
from allsafe_fast import Auth, AuthConfig, ConfigurationError
# This will raise ConfigurationError in production
try:
auth = Auth(AuthConfig(
secret_key="change-me-please-...", # Default key!
env="production",
))
except ConfigurationError as e:
print(str(e))
# "Default secret key cannot be used in production"
# This will also raise ConfigurationError
try:
auth = Auth(AuthConfig(
secret_key="strong-unique-secret-key",
env="production",
cookie_secure=False, # Insecure cookies!
))
except ConfigurationError as e:
print(str(e))
# "Cookie secure must be true in production"
Configuration Validators
Beyond the production guards, AllSafe Fast validates all configuration values at startup:
- Secret key — Must be non-empty. An empty secret key raises
ConfigurationError. - Cookie SameSite — Must be one of
lax,strict, ornone. Any other value raisesConfigurationError. - Environment — Must be one of
development,production,staging, ortest. Any other value raisesConfigurationError.
# AuthConfig validates all values at construction time
config = AuthConfig(
secret_key="my-secret",
cookie_same_site="lax", # Valid: lax, strict, none
env="production", # Valid: development, production, staging, test
)
# Check if running in production
print(config.is_production) # True
# Dump config as dictionary (secrets redacted)
print(config.model_dump())
For a complete pre-deployment checklist, see the Production Checklist page. For rate limiting details, see Rate Limiting.