Skip to main content
Validated by Zod in lib/env.ts at boot. A failure throws a message naming the field rather than surfacing later as a confusing runtime error.

Required

AUTH_SECRET is more load-bearing than it looks. It signs sessions and derives the encryption key for stored TOTP secrets via HKDF.Rotating it invalidates every session and makes every stored 2FA secret undecryptable — enrolled users must fall back to a recovery code and re-enrol. Not a routine operation.To rotate without dropping sessions, @auth/core accepts an array and tries each in order: secret: [newSecret, previousSecret] in auth.config.ts, newest first.

Optional

Everything below is optional. Each degrades a specific feature rather than breaking the app.

Authentication providers

Providers are added conditionally, so an unset id removes the button rather than producing a broken one.

Email

RESEND_FROM must be email@example.com or Name <email@example.com>. Checked at boot, because a malformed sender otherwise surfaces as a 422 the first time someone resets a password.

Object storage

Any S3-compatible service: AWS S3, Cloudflare R2, Backblaze B2, MinIO.
Without a bucket, KYC uploads fall back to a development-only local directory. Do not run production that way.

Payments

The API key without the IPN secret is the dangerous half-configuration: addresses get handed out and money arrives, but every callback that would credit it fails signature verification.Boot fails if the key is set without the other two, so this cannot be discovered at deposit time.

Signal engine

A relative or half-typed URL fails at fetch time and looks identical to the engine being down — one is a config typo and the other is an outage, so the URL is validated at boot.

Assistant

Status page

Scheme is validated rather than just parsed. A javascript: URL parses perfectly well and would put a script sink in the footer of every page — only http and https pass.The status page is hosted off this infrastructure on purpose: a status page served by the app it reports on says nothing during the outage that matters most.

Media

Cross-field rules

Production checklist

  • AUTH_SECRET generated fresh, not copied from development
  • DATABASE_URL points at production with connection limits set
  • S3 bucket configured — not the local fallback
  • NOWPAYMENTS_IPN_SECRET set alongside the API key
  • RESEND_API_KEY and a verified RESEND_FROM
  • AUTH_URL set to the real origin
  • STATUS_PAGE_URL pointing at a monitor hosted elsewhere