Radondocs

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.

lib/auth.ts
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

adapterRadonAdapterrequired

The bridge to your database — where users, identities, codes, and sessions live. See Adapters for every built-in and how to write your own.

sessionSdkSessionConfigrequired

JWT session settings. session.secret is the only strictly required field — see session below.

providersProvidersConfig

Which sign-in methods to enable. Anything you leave out stays off and never ships in your bundle — see providers below.

appNamestring

Shown in the default email and SMS copy ("Your Acme code is…"). Also the default TOTP issuer and WebAuthn relying-party name.

codeCodeConfig

One-time-code engine settings — length, lifetime, attempts. See code below.

rateLimitRateLimitConfig

Per-identifier send throttling. See rateLimit below.

licenseKeystring

Radon 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.

licenseLicenseConfig

Advanced license configuration (endpoint, watermark, injectable fetch). See license below.

encryptionKeystring

32-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) => void

Called when an event handler throws. Defaults to console.error.

hasherHasher

Override 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() => Date

Injectable 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.

secretstringrequired

JWT signing secret. Set it from an environment variable, e.g. process.env.RADON_SECRET. If it leaks, anyone can forge logins.

expiresInSecnumberdefault: 604800

Session lifetime in seconds. Default is 7 days.

issuerstring

Optional JWT iss claim.

audiencestring

Optional JWT aud claim.

clockToleranceSecnumberdefault: 0

Seconds 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

emailCodeEmailCodeConfig

6-digit codes by email. { sender, template?, from? }sender required. See Email code.

magicLinkMagicLinkConfig

One-click sign-in links. { sender, baseUrl, ttlMs?, template?, from? }sender and baseUrl required; ttlMs defaults to 15 minutes. See Magic link.

emailPasswordEmailPasswordConfig

Signup/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.

googleGoogleConfig

Google 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>Pro

50 OAuth providers keyed by a name you choose, e.g. { github: { preset: "github", clientId, clientSecret, redirectUri } }. See OAuth.

phoneOtpPhoneOtpConfigPro

SMS one-time codes. { sender, ttlMs?, template?, from? }sender is an SmsSender (e.g. twilioSender()); ttlMs defaults to 5 minutes. See Phone.

totpTotpConfigPro

Authenticator-app 2FA. { issuer?, totp?, window? }issuer defaults to appName; window defaults to 1 step (±30s). Requires encryptionKey. See TOTP.

webauthnWebAuthnConfigPro

Passkeys. { rpID, origin, rpName? }rpID (registrable domain) and origin (full URL, or an array) are required; rpName defaults to appName. See Passkeys.

refreshRefreshConfigPro

Short access token + long refresh token with rotation. { accessTtlSec?, refreshTtlMs?, refreshTokenBytes? } — defaults 900s / 30 days / 32 bytes. See Refresh tokens.

sessionsSessionsConfigPro

Multi-device sessions, guests, impersonation. Enable with {}. See Multi-device sessions.

apiKeysApiKeysConfigPro

Service-to-service / CLI keys. { keyPrefix?, secretBytes? } — defaults "rk" / 24 bytes. See API keys.

orgsOrgsConfigPro

Orgs / teams. { sender?, inviteUrl?, from? } — a sender is only needed to email invites. See Orgs.

accountAccountConfigPro

GDPR 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: 6

Number of characters in a generated code.

charset"numeric" | "alphanumeric" | "alphabetic"default: "numeric"

Character set to draw from.

alphabetstring

Explicit alphabet. Overrides charset when provided.

ttlMsnumberdefault: 600000

Milliseconds a code stays valid. Default is 10 minutes.

maxAttemptsnumberdefault: 5

Failed 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: 3

Sends allowed per identifier per window.

windowMsnumberdefault: 600000

Window 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.

keystring

The license key. Falls back to RADON_LICENSE_KEY.

verifyUrlstring

Verify endpoint. Falls back to RADON_LICENSE_URL, then the hosted service.

watermarkbooleandefault: true

Print the [radon] licensed to: a***@example.com console line on a successful check at init.

fetchtypeof fetch

Injectable 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.

.env
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.

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):

app/api/auth/[...radon]/route.ts
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

RadonSdkConfig
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
}

On this page