Configuration
Every option the Radon constructor accepts, what it does, and when to change it.
The Radon constructor takes one options object. Only adapter and session
are strictly required; everything else has a sensible default or is only needed
for a specific feature.
export const auth = new Radon({
adapter: postgresAdapter(pool), // required — where users live
session: { secret: process.env.RADON_SECRET! }, // required — signs JWTs
appName: "Acme", // shown in default email copy
providers: { /* the sign-in methods you enable */ },
code: { length: 6, ttlMs: 600_000, maxAttempts: 5 },
rateLimit: { maxPerWindow: 3, windowMs: 600_000 },
});adapter — where users live
The bridge to your database. Required. See Adapters for every built-in option and how to write your own.
adapter: postgresAdapter(pool)session — JWT session settings
Required (session.secret specifically). Radon issues stateless JWT
session tokens: the token is a signed value in an HttpOnly cookie, verified
without a database read. The same secret also signs magic-link and
password-reset tokens.
session: {
secret: process.env.RADON_SECRET!, // required
expiresInSec: 7 * 24 * 60 * 60, // default: 7 days
issuer: "acme", // optional JWT `iss` claim
audience: "acme-app", // optional JWT `aud` claim
clockToleranceSec: 0, // skew tolerance on verify
}Want revocable, per-device sessions?
Stateless JWTs can't be revoked individually before they expire. If you need "log out this one device" or a live list of active sessions, add the Pro multi-device sessions or refresh tokens providers, which are database-backed and revocable.
providers — the sign-in methods
Opt into the methods you want; leave the rest out. Each is documented on its own Auth Methods page. The free-tier providers:
providers: {
emailCode: { sender, template?, from? },
magicLink: { sender, baseUrl, ttlMs?, template?, from? },
emailPassword: { sender, resetUrl, hasher?, minLength?, resetTemplate?, from? },
google: { clientId?, clientSecret?, redirectUri?, scopes?, fetch? },
}sender is an email sender. baseUrl (magic link) and
resetUrl (password) are where those links point in your app. Google
credentials fall back to the RADON_GOOGLE_CLIENT_ID,
RADON_GOOGLE_CLIENT_SECRET, and RADON_GOOGLE_REDIRECT_URI env vars.
Pro providers (oauth, phoneOtp, totp, webauthn, refresh, sessions,
apiKeys, orgs, account) live under the same providers key — see
Radon Pro.
appName — email branding
A string shown in the default email templates ("Your Acme code is…"). Also the default issuer for TOTP and relying-party name for passkeys.
appName: "Acme"code — one-time-code engine
Controls every 6-digit code (email codes, phone OTP) Radon issues.
code: {
length: 6, // digits in the code (default 6)
ttlMs: 600_000, // lifetime in ms (default 10 minutes)
maxAttempts: 5, // wrong tries before the code locks (default 5)
}rateLimit — abuse protection
Radon rate-limits code/link sends per identifier out of the box. Tune it:
rateLimit: {
maxPerWindow: 3, // sends allowed per window (default 3)
windowMs: 600_000, // window length in ms (default 10 minutes)
}A caller over the limit gets a RateLimitError (HTTP 429) carrying
retryAfterMs.
Pro & security options
| Option | Purpose |
|---|---|
licenseKey | Radon Pro license key. Falls back to RADON_LICENSE_KEY. Verified in auth.init(). See Pro. |
license | Advanced license config ({ key?, verifyUrl?, watermark?, fetch? }). |
encryptionKey | 32-byte key for encryption-at-rest of reversible secrets (TOTP). Falls back to RADON_ENCRYPTION_KEY. |
onEventError | (error, event) => void — called when an event handler throws. |
hasher | Override the engine's code/token hasher (SHA-256 by default). |
now | Injectable clock (() => Date) for testing. |
Cookie & handler options
The session cookie's name and security flags are configured at the framework
handler, not on the Radon instance. They're secure by default (HttpOnly,
Secure, SameSite=Lax, name radon_session):
const handler = radonNextHandler(auth, {
basePath: "/api/auth",
cookieName: "acme_session", // rename the cookie
cookieOptions: { sameSite: "lax", domain: ".acme.com" },
successRedirect: "/dashboard", // after magic-link / OAuth callback
failureRedirect: "/signin?error=1",
});sameSite and OAuth
If you embed auth in a cross-site iframe you may need sameSite: "none" with
secure: true (browsers reject None without Secure). Otherwise keep "lax"
— it's safer against CSRF.
Full type
interface RadonSdkConfig {
adapter: RadonAdapter; // required
session: {
secret: string; // required
expiresInSec?: number; // default 604800 (7 days)
issuer?: string;
audience?: string;
clockToleranceSec?: number;
};
providers?: ProvidersConfig;
appName?: string;
code?: { length?: number; ttlMs?: number; maxAttempts?: number };
rateLimit?: { maxPerWindow?: number; windowMs?: number };
licenseKey?: string;
license?: { key?: string; verifyUrl?: string; watermark?: boolean; fetch?: typeof fetch };
encryptionKey?: string;
onEventError?: (error: unknown, event: string) => void;
hasher?: Hasher;
now?: () => Date;
}