Skip to content

Configuration

FastAuthOptions is a plain pydantic.BaseModel. Every nested section is also a BaseModel with extra="forbid", so a typo in any field name is caught at construction rather than at runtime. The framework never reads environment variables, .env files, AWS Secrets Manager, Vault, or any other external source — every value comes from the constructor. Pydantic v2 validation runs eagerly on the entire tree at instantiation.

Loading config from your source of choice is the consumer's job. The example below uses ordinary local variables to emphasize that fastauth only sees the final values you pass to the constructor.

Construction

from pydantic import SecretStr
from pymongo import AsyncMongoClient
from fastauth import FastAuth, FastAuthOptions
from fastauth.database import mongo, postgres
from fastauth.options import (
    AppOptions,
    CookieOptions,
    RateLimitOptions,
    SessionOptions,
)
from fastauth import email_password

app_secret = "replace-me-with-your-application-secret"
mongo_url = "mongodb://db.example.com:27017"
mongo_client = AsyncMongoClient(mongo_url, uuidRepresentation="standard")
mongo_database = mongo_client["myapp"]

options = FastAuthOptions(
    secret_key=SecretStr(app_secret),
    database=mongo(
        database=mongo_database,
        collection_prefix="tenant_",
        collection_suffix="_auth",
    ),
    app=AppOptions(base_url="https://app.example.com"),
    session=SessionOptions(expires_in="7d"),
    cookie=CookieOptions(same_site="strict"),
    rate_limit=RateLimitOptions(storage="database"),
)
auth = FastAuth(options, plugins=[email_password()])
print(options.database.collection_prefix)

postgres_options = FastAuthOptions(
    secret_key=SecretStr(app_secret),
    database=postgres(
        url="postgresql+asyncpg://user:pass@db.example.com/app",
        table_prefix="fastauth_",
        table_suffix="_auth",
    ),
)
postgres_auth = FastAuth(postgres_options, plugins=[email_password()])
print(postgres_options.database.url)
print(postgres_options.database.table_suffix)

If you use a vault or parameter store, read those values in your application configuration layer and pass the resulting strings into FastAuthOptions.

Sections

FastAuthOptions composes focused Pydantic sections:

Section Purpose
secret_key, secret_key_rotation HMAC for signed cookies and KEK for JWKS private keys; rotation list is checked on decrypt.
app Application name, base URL, base path.
session DB-backed vs JWT strategy, expiry, idle timeout.
cookie Cookie name, path, domain, Secure/HttpOnly/SameSite attributes.
password Argon2id memory/time/parallelism, minimum password length.
email From-address, subject lines, optional template directory, and shared template globals.
email_verification Token TTL, callback path or override URL, whether sign-in requires a verified email.
password_reset Token TTL, callback path or override URL.
email_change Token TTL, callback path or override URL, email subject.
delete_account Token TTL, callback path or override URL, account-deletion email subject.
rate_limit Window, max requests, storage backend (memory or DB).
csrf Trusted origins, relative-path policy, enable/disable.
lockout Account-lockout policy (max_failures, window).
database Database option object from memory(), mongo(database=...), postgres(url=...), or custom(adapter=..., backend=...).
proxy Trusted reverse proxies and the forwarding header to honor for client IP resolution.
production_safety Independent HTTPS, cookie, database, email-sender, and migration policies used in production.
advanced IPv6 subnet bucket size and __Secure- cookie prefix flag.

Pass any subset of sections to override the defaults; omitted sections get the BaseModel default_factory values.

Plugins are behavior objects passed to FastAuth(..., plugins=[...]), not a FastAuthOptions field. Plugin presence is the feature switch.

database defaults to memory(). For persistent deployments, pass mongo(database=...) or postgres(url=...) explicitly.

custom(adapter=adapter) defaults to DatabaseBackendKind.MEMORY, which production validation rejects. Custom production adapters must declare their real backend, for example custom(adapter=adapter, backend=DatabaseBackendKind.POSTGRES).

HTTP field names

Python models use snake_case field names. Public HTTP request and response models use Pydantic aliases, so JSON and OpenAPI expose camelCase names such as emailVerified, refreshToken, userId, and includeRefreshToken.

Request bodies accept both Python field names and aliases, but responses emit one stable camelCase shape. There is no runtime-selectable casing mode.

Usernames are case-sensitive. For example, Bhargav and bhargav are distinct usernames and must be treated as separate values by adapters.

First-party plugin duration options accept timedelta, numeric seconds, and compact strings such as "10m" and "7d". EmailPasswordOptions also exposes require_username and allow_username_change; both default to False.

Shared values for custom email templates belong in EmailOptions.template_globals. Per-message values such as OTPs and callback URLs take precedence over globals with the same key.

Why no process config loader?

Earlier versions shipped an FastAuthEnvConfig subclass that layered pydantic-settings on top of the base model. That class has been removed. The reasoning:

  • Tests want to construct config explicitly; an env-loader path forces them to monkey-patch process-global state for every test, which leaks between tests and obscures intent.
  • Production deployments increasingly use vaults, parameter stores, or Kubernetes Secrets. Having the framework hard-code one loading convention narrowed the integration surface unnecessarily.
  • Keeping config loading outside the framework makes the source explicit at the application boundary.

The application boundary should look like any other dependency injection:

from fastauth import FastAuthOptions
from fastauth.database import mongo
from fastauth import email_password
from pydantic import SecretStr

options = FastAuthOptions(
    secret_key=SecretStr(app_settings.auth_secret),
    database=mongo(database=app_settings.mongo_database),
)
auth = FastAuth(options, plugins=[email_password()])