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:

ThreatMitigationConfigurationOperational
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) and aud (audience) claims for validation.
Token TypeLifetimeStoragePurpose
Access token (JWT)900s (15 min)Client-side (cookie/header)API authentication
Refresh token2592000s (30 days)Hashed in databaseObtain new access tokens
Verification tokenConfigurableHashed in databaseEmail 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 Authorization header instead of cookies, which is inherently CSRF-resistant.
  • Configurable SameSite — You can set SameSite=Strict for maximum protection or SameSite=None (requires Secure) 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 limitsALLSAFE_RATE_LIMIT (default: 5) and ALLSAFE_RATE_LIMIT_WINDOW (default: 900s).

AllSafe Fast sets cookies with security-focused attributes by default:

HttpOnly
Cookies are not accessible via JavaScript (document.cookie), preventing XSS-based token theft. Default: true.
Secure
Cookies are only sent over HTTPS connections. Default: true. Must be true in production.
SameSite
Controls cross-site cookie sending. lax (default) provides CSRF protection. Options: lax, strict, none.
AttributeDefaultEnv VariableProduction Requirement
HttpOnlytrueALLSAFE_COOKIE_HTTP_ONLYMust be true
SecuretrueALLSAFE_COOKIE_SECUREMust be true
SameSitelaxALLSAFE_COOKIE_SAME_SITEMust 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:

🔒 Production Guard — Rejects Default Secret Key

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.

🔒 Production Guard — Rejects Insecure Cookies

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, or none. Any other value raises ConfigurationError.
  • Environment — Must be one of development, production, staging, or test. Any other value raises ConfigurationError.
# 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())
💡 See Also

For a complete pre-deployment checklist, see the Production Checklist page. For rate limiting details, see Rate Limiting.