Password hashing
Better Auth uses thescrypt algorithm to hash passwords by default. scrypt
is memory-hard and CPU-intensive, making it resistant to brute-force and
graphics card attacks.
You can supply a custom implementation via the
emailAndPassword.password option:
Secret key management
Thesecret option (or BETTER_AUTH_SECRET
environment variable) is used for encryption and signing. Keep this value out
of your source code.
Secret rotation
Better Auth supports non-destructive secret rotation via thesecrets option. Encrypted data uses an
envelope format that embeds the key version, so you can add a new key without
invalidating existing sessions.
secret. Data is lazily re-encrypted with the current key on next write. No
database migrations or downtime required.
CSRF protection
Better Auth uses multiple layers to prevent Cross-Site Request Forgery:1. Non-simple request requirement
1. Non-simple request requirement
Better Auth only accepts requests with a non-simple
Content-Type header
(i.e. application/json), which browsers will not send without a preflight
check. This eliminates most naive CSRF vectors.2. Origin validation
2. Origin validation
Every request’s
Origin header is verified against your baseURL and the
trustedOrigins list. Requests from untrusted origins are rejected with a
403.3. SameSite cookies
3. SameSite cookies
4. Fetch Metadata protection (first-login CSRF)
4. Fetch Metadata protection (first-login CSRF)
For sign-in and sign-up routes that accept form submissions, Better Auth
uses Fetch Metadata headers
(
Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest) to block cross-site
navigation requests when no session cookie is present.Browsers that do not send Fetch Metadata headers fall back to the standard
origin validation path.5. No state mutations on GET requests
5. No state mutations on GET requests
GET requests are treated as read-only. Where a GET must trigger a mutation
(e.g. OAuth callbacks), Better Auth validates
nonce and state parameters
to confirm request authenticity.Disabling security checks
| Option | What it disables |
|---|---|
advanced.disableCSRFCheck | CSRF protection only (origin header validation, Fetch Metadata) |
advanced.disableOriginCheck | URL validation and CSRF protection (backward compatibility) |
Session security
Expiration and rolling refresh
Sessions expire after 7 days by default. Each time a session is used, if its age exceeds theupdateAge threshold (default: 1 day) the expiry is extended.
Session revocation
Authenticated users can revoke individual sessions or all sessions. This immediately invalidates the selected session tokens. See session management for details.Secure cookies
Better Auth automatically sets theSecure cookie flag when baseURL uses
https. Cookies are also HttpOnly by default to prevent JavaScript access.
For cross-subdomain authentication:
Trusted origins
Trusted origins prevent CSRF attacks and block open redirects. Requests from origins not on this list are automatically rejected.Wildcard patterns
Dynamic origins
Dynamic origin functions are called on every request. Avoid slow database
queries here, or cache the result.
Rate limiting
Better Auth includes built-in rate limiting on all routes. Sensitive routes (sign-in, sign-up, password reset) have stricter default limits. Configure rate limiting inrateLimit:
IP address handling
Better Auth uses client IP addresses for rate limiting and security monitoring. Configure which header to trust:Ensure your proxy is configured to set the header you configure here, and
that end users cannot forge it. In development,
127.0.0.1 is used as a
fallback when no IP can be determined.Trusted proxy headers
When running behind a reverse proxy you can derivebaseURL from
X-Forwarded-Host and X-Forwarded-Proto:
trustedProxyHeaders is enabled:
- Static
baseURLfrom config (proxy headers ignored) BETTER_AUTH_URLenvironment variableX-Forwarded-Host+X-Forwarded-Protoheaders- Request URL origin (final fallback)
OAuth state and PKCE
Better Auth stores OAuthstate and PKCE code_verifier values per-request
to prevent CSRF attacks and code-injection threats. These are deleted
automatically after the OAuth flow completes.
Email enumeration protection
WhenrequireEmailVerification is enabled or autoSignIn is false, the
sign-up endpoint returns the same 200 response whether or not the email is
already registered. Timing attacks are mitigated by simulating password hashing
for duplicate attempts, following
OWASP authentication best practices.