Configuration
Every option the Radon constructor accepts — types, defaults, and when to change it. Only adapter and session are required; everything else is opt-in.
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.
import { Radon } from "@radonsdk/auth";
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: { emailCode: { sender } }, // the sign-in methods you enable
code: { length: 6, ttlMs: 600_000, maxAttempts: 5 },
rateLimit: { maxPerWindow: 3, windowMs: 600_000 },
});Top-level options
adapterRadonAdapterrequiredThe bridge to your database — where users, identities, codes, and sessions live. See Adapters for every built-in and how to write your own.
sessionSdkSessionConfigrequiredJWT session settings. session.secret is the only strictly required field —
see session below.
providersProvidersConfigWhich sign-in methods to enable. Anything you leave out stays off and never
ships in your bundle — see providers below.
appNamestringShown in the default email and SMS copy ("Your Acme code is…"). Also the default TOTP issuer and WebAuthn relying-party name.
codeCodeConfigOne-time-code engine settings — length, lifetime, attempts. See
code below.
rateLimitRateLimitConfigPer-identifier send throttling. See rateLimit below.
licenseKeystringRadon Pro license key. Required once any Pro provider is configured. Falls
back to the RADON_LICENSE_KEY env var. Verified in auth.init(). See
Radon Pro.
licenseLicenseConfigAdvanced license configuration (endpoint, watermark, injectable fetch). See
license below.
encryptionKeystring32-byte symmetric key for encryption-at-rest of reversible secrets (TOTP
secrets). Falls back to RADON_ENCRYPTION_KEY. Accepts hex, base64, or
base64url. Generate with openssl rand -hex 32.
onEventError(error: unknown, event: string) => voidCalled when an event handler throws.
Defaults to console.error.
hasherHasherOverride the engine's code/token hasher. Defaults to SHA-256 with constant-time comparison (appropriate for high-entropy single-use secrets — not a password KDF).
now() => DateInjectable clock, primarily for testing. Defaults to () => new Date().
session — JWT session settings
Required (session.secret specifically). Radon issues stateless JWT
session tokens: a signed value in an HttpOnly cookie, verified without a database
read. The same secret also signs magic-link and password-reset tokens.
secretstringrequiredJWT signing secret. Set it from an environment variable, e.g.
process.env.RADON_SECRET. If it leaks, anyone can forge logins.
expiresInSecnumberdefault: 604800Session lifetime in seconds. Default is 7 days.
issuerstringOptional JWT iss claim.
audiencestringOptional JWT aud claim.
clockToleranceSecnumberdefault: 0Seconds of clock skew tolerated when verifying exp / nbf.
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. All provider configs — free and Pro — live under this one key.
Free providers
emailCodeEmailCodeConfig6-digit codes by email. { sender, template?, from? } — sender required.
See Email code.
magicLinkMagicLinkConfigOne-click sign-in links. { sender, baseUrl, ttlMs?, template?, from? } —
sender and baseUrl required; ttlMs defaults to 15 minutes. See
Magic link.
emailPasswordEmailPasswordConfigSignup/login + reset. { sender, resetUrl?, hasher?, minLength?, resetTemplate?, from? }.
resetUrl is required to use requestReset; hasher defaults to bcrypt
(cost 10); minLength defaults to 8. See Password.
googleGoogleConfigGoogle OAuth. { clientId?, clientSecret?, redirectUri?, scopes?, fetch? } —
credentials fall back to RADON_GOOGLE_CLIENT_ID, RADON_GOOGLE_CLIENT_SECRET,
RADON_GOOGLE_REDIRECT_URI; scopes default to openid email profile. See
Google.
Pro providers
Configuring any of these makes a license required. Full details in Radon Pro.
oauthRecord<string, OAuthProviderConfig>Pro50 OAuth providers keyed by a name you choose, e.g.
{ github: { preset: "github", clientId, clientSecret, redirectUri } }. See
OAuth.
phoneOtpPhoneOtpConfigProSMS one-time codes. { sender, ttlMs?, template?, from? } — sender is an
SmsSender (e.g. twilioSender()); ttlMs defaults to 5 minutes. See
Phone.
totpTotpConfigProAuthenticator-app 2FA. { issuer?, totp?, window? } — issuer defaults to
appName; window defaults to 1 step (±30s). Requires encryptionKey. See
TOTP.
webauthnWebAuthnConfigProPasskeys. { rpID, origin, rpName? } — rpID (registrable domain) and
origin (full URL, or an array) are required; rpName defaults to appName.
See Passkeys.
refreshRefreshConfigProShort access token + long refresh token with rotation. { accessTtlSec?, refreshTtlMs?, refreshTokenBytes? }
— defaults 900s / 30 days / 32 bytes. See Refresh tokens.
sessionsSessionsConfigProMulti-device sessions, guests, impersonation. Enable with {}. See
Multi-device sessions.
apiKeysApiKeysConfigProService-to-service / CLI keys. { keyPrefix?, secretBytes? } — defaults "rk"
/ 24 bytes. See API keys.
orgsOrgsConfigProOrgs / teams. { sender?, inviteUrl?, from? } — a sender is only needed to
email invites. See Orgs.
accountAccountConfigProGDPR export + deletion. Enable with {}. See Account.
code — one-time-code engine
Controls every code (email codes, phone OTP) and the underlying tokens Radon issues.
lengthnumberdefault: 6Number of characters in a generated code.
charset"numeric" | "alphanumeric" | "alphabetic"default: "numeric"Character set to draw from.
alphabetstringExplicit alphabet. Overrides charset when provided.
ttlMsnumberdefault: 600000Milliseconds a code stays valid. Default is 10 minutes.
maxAttemptsnumberdefault: 5Failed verification attempts before a code is locked.
One active code per identifier
Issuing a fresh code invalidates any previous active code for the same (identifier, purpose). Only the newest code verifies — a user who requests a second code can't sign in with the first.
rateLimit — abuse protection
Radon rate-limits code and link sends per identifier out of the box.
maxPerWindownumberdefault: 3Sends allowed per identifier per window.
windowMsnumberdefault: 600000Window length in milliseconds. Default is 10 minutes.
Over the limit throws a 429
A caller past the limit gets a RateLimitError (HTTP 429) carrying
retryAfterMs. With the defaults that's more than 3 sends to the same address in
10 minutes. Surface the retry hint to users so they wait rather than hammer.
license — advanced Pro licensing
Most apps just set licenseKey (or the RADON_LICENSE_KEY env var). Use the
license object for finer control.
keystringThe license key. Falls back to RADON_LICENSE_KEY.
verifyUrlstringVerify endpoint. Falls back to RADON_LICENSE_URL, then the hosted service.
watermarkbooleandefault: truePrint the [radon] licensed to: a***@example.com console line on a
successful check at init.
fetchtypeof fetchInjectable fetch (proxies, tests).
Verified once, cached for the process
auth.init() pings the license service at most once per process and caches
the result — never per auth request. A confirmed-invalid key or a network
failure throws LicenseInvalidError (it fails closed), so a Pro app won't
silently boot unlicensed.
encryptionKey — secrets at rest
Some Pro features store a reversible secret that must be read back (a TOTP secret, to verify codes). Those can't just be hashed — they're encrypted with AES-256-GCM keyed by this value.
RADON_ENCRYPTION_KEY=$(openssl rand -hex 32)TOTP needs this key
Without an encryptionKey (or the RADON_ENCRYPTION_KEY env var), TOTP
enrollment throws EncryptionRequiredError. Everything that can be one-way
hashed (codes, session tokens, refresh tokens, API keys, passwords) already is,
and needs no key.
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; // default 0
};
providers?: ProvidersConfig;
appName?: string;
code?: {
length?: number; // default 6
charset?: "numeric" | "alphanumeric" | "alphabetic"; // default "numeric"
alphabet?: string;
ttlMs?: number; // default 600_000 (10 min)
maxAttempts?: number; // default 5
};
rateLimit?: { maxPerWindow?: number; windowMs?: number }; // 3 / 600_000
licenseKey?: string; // Pro; falls back to RADON_LICENSE_KEY
license?: { key?: string; verifyUrl?: string; watermark?: boolean; fetch?: typeof fetch };
encryptionKey?: string; // TOTP; falls back to RADON_ENCRYPTION_KEY
onEventError?: (error: unknown, event: string) => void;
hasher?: Hasher; // default SHA-256
now?: () => Date; // testing
}