API reference
The full Radon surface — the constructor, provider methods, session helpers, HTTP routes, entities, and error codes.
A complete reference to the @radonsdk/auth public API. For guided walkthroughs,
start with the Quickstart or an auth method.
new Radon(config)
Creates the SDK instance. See Configuration for every option in detail.
import { Radon } from "@radonsdk/auth";
const auth = new Radon({
adapter, // required
session: { secret: process.env.RADON_SECRET! }, // required
providers: { /* enabled methods */ },
appName: "Acme",
code: { length: 6, ttlMs: 600_000, maxAttempts: 5 },
rateLimit: { maxPerWindow: 3, windowMs: 600_000 },
licenseKey: process.env.RADON_LICENSE_KEY, // Pro
encryptionKey: process.env.RADON_ENCRYPTION_KEY, // TOTP
});createRadon(config) is an equivalent factory function.
Instance methods
| Member | Signature | Description |
|---|---|---|
init() | () => Promise<void> | Create tables (SQL adapters) and verify the Pro license. Call once on boot. |
close() | () => Promise<void> | Adapter teardown. |
createSessionToken() | (userId, { claims?, expiresInSec? }?) => { token, expiresAt } | Issue a JWT session token. |
verifyToken() | (token) => JwtClaims | Verify a token; throws if invalid/expired. claims.sub is the user id. |
getSessionUser() | (token) => Promise<RadonUser> | Verify + load the user (sanitized). |
on() | (event, handler) => Unsubscribe | Subscribe to an event. Pro. |
licensed | boolean | Whether the Pro tier is unlocked. |
Provider accessors
Each returns the provider or throws ProviderNotConfiguredError if it wasn't
enabled. Pro accessors also require a verified license.
| Accessor | Provider | Tier |
|---|---|---|
auth.emailCode | Email one-time code | Free |
auth.magicLink | Magic link | Free |
auth.emailPassword | Email + password | Free |
auth.google | Google OAuth | Free |
auth.oauth(name) | A configured OAuth provider | Pro |
auth.phoneOtp | Phone / SMS OTP | Pro |
auth.totp | 2FA / TOTP | Pro |
auth.webauthn | Passkeys / WebAuthn | Pro |
auth.refresh | Refresh tokens | Pro |
auth.sessionsProvider | Multi-device sessions | Pro |
auth.apiKeys | API keys | Pro |
auth.orgs | Orgs / teams | Pro |
auth.account | Data export / deletion | Pro |
Provider methods
auth.emailCode
sendCode({ email, metadata? }): Promise<{ expiresAt: Date }>
verify({ email, code }): Promise<{ user: RadonUser; created: boolean }>auth.magicLink
sendLink({ email, redirectTo?, metadata? }): Promise<{ url: string; expiresAt: Date }>
verify(signedToken): Promise<{ user: RadonUser; created: boolean }>auth.emailPassword
signup({ email, password, metadata? }): Promise<{ user: RadonUser }>
login({ email, password }): Promise<{ user: RadonUser }>
requestReset({ email, redirectTo? }): Promise<{ sent: boolean }>
setPassword({ token, newPassword }): Promise<{ user: RadonUser }>auth.google
getAuthUrl({ state?, scopes?, accessType?, prompt?, loginHint? }): string
handleCallback(code): Promise<{ user: RadonUser; created: boolean; profile: GoogleProfile }>auth.oauth(name) (Pro)
getAuthUrl({ state?, scopes?, params? }): { url: string; codeVerifier?: string; state?: string }
handleCallback({ code, codeVerifier? }): Promise<{ user; created; profile; tokens }>
// auth.oauthProviders → string[] of configured provider namesauth.phoneOtp (Pro)
sendCode({ phone, metadata? }): Promise<{ expiresAt: Date }>
verify({ phone, code }): Promise<{ user: RadonUser; created: boolean }>auth.totp (Pro)
beginEnrollment(userId): Promise<{ secret: string; uri: string }>
confirmEnrollment(userId, code): Promise<{ recoveryCodes: string[] }>
verify(userId, code): Promise<boolean>
verifyRecoveryCode(userId, code): Promise<boolean>
isEnabled(userId): Promise<boolean>
regenerateRecoveryCodes(userId): Promise<string[]>
disable(userId): Promise<void>auth.webauthn (Pro)
startRegistration(userId): Promise<{ options; challenge: string }>
finishRegistration({ userId, response, expectedChallenge }): Promise<{ credential }>
startAuthentication(userId?): Promise<{ options; challenge: string }>
finishAuthentication({ userId?, response, expectedChallenge }): Promise<{ user: RadonUser }>
listCredentials(userId): Promise<Array<Omit<StoredCredential, "publicKey">>>
removeCredential(userId, credentialId): Promise<void>auth.refresh (Pro)
issue({ userId, claims?, device? }): Promise<TokenPair>
refresh(refreshToken, { claims?, device? }?): Promise<TokenPair>
revoke(refreshToken): Promise<void>
revokeAllForUser(userId): Promise<void>
// TokenPair = { accessToken, accessExpiresAt, refreshToken, refreshExpiresAt, familyId }auth.sessionsProvider (Pro)
create({ userId, device?, ttlMs? }): Promise<{ token; session }>
listDevices(userId, currentToken?): Promise<DeviceSession[]>
revokeDevice(sessionId): Promise<void>
revoke(token): Promise<void>
revokeAll(userId): Promise<void>
createGuest({ device?, metadata? }?): Promise<{ user; token; session }>
isGuest(userId): Promise<boolean>
upgrade({ userId, provider, providerAccountId, email?, emailVerified? }): Promise<{ user }>
impersonate(adminUserId, targetUserId, { expiresInSec?, reason? }?): Promise<{ token; expiresAt }>auth.apiKeys (Pro)
create({ userId?, orgId?, name, scopes?, expiresAt?, metadata? }): Promise<{ key; record }>
verify(presentedKey): Promise<PublicApiKey>
list({ userId?, orgId? }): Promise<PublicApiKey[]>
revoke(apiKeyId): Promise<void>auth.orgs (Pro)
create({ name, slug?, ownerUserId, metadata? }): Promise<{ org; membership }>
get(idOrSlug): Promise<RadonOrg | null>
listForUser(userId): Promise<RadonOrgMembership[]>
listMembers(orgId): Promise<RadonOrgMembership[]>
roleOf(orgId, userId): Promise<OrgRole | null>
invite({ orgId, email, role?, invitedByUserId? }): Promise<{ invite; token; url? }>
acceptInvite(token, userId): Promise<RadonOrgMembership>
addMember(orgId, userId, role?): Promise<RadonOrgMembership>
setRole(orgId, userId, role): Promise<RadonOrgMembership>
removeMember(orgId, userId): Promise<void>
assertRole(orgId, userId, min): Promise<void>
delete(orgId): Promise<void>auth.account (Pro)
exportData(userId): Promise<UserDataExport>
deleteUser(userId): Promise<void>Standalone helpers
Verify a session token anywhere without a Radon instance — same secret:
import { verifyToken } from "@radonsdk/auth";
const claims = verifyToken(cookieValue, process.env.RADON_SECRET!, {
clockToleranceSec: 0, // optional
});
// claims.sub is the user idHTTP routes
Mounted by every framework integration, relative to your base
path (e.g. /api/auth). A successful sign-in sets an HttpOnly, SameSite=Lax
cookie named radon_session.
| Method & path | Body / query | Effect |
|---|---|---|
POST /email-code/send | { email } | Emails a 6-digit code |
POST /email-code/verify | { email, code } | Signs in → cookie |
POST /magic-link/send | { email } | Emails a sign-in link |
GET /magic-link/verify | ?token=… | Signs in → cookie, redirects |
POST /password/signup | { email, password } | Creates account → cookie |
POST /password/login | { email, password } | Signs in → cookie |
POST /password/request-reset | { email } | Emails a reset link (always 200) |
POST /password/reset | { token, newPassword } | Sets a new password |
GET /google/start | ?state=… | Redirects to Google |
GET /google/callback | ?code=… | Signs in → cookie, redirects |
POST /logout | — | Clears the session cookie |
GET /session | — | { user } or 401 |
Errors come back as { error: "<code>", message } with the status from the table
below.
Entities
The records adapters store and return.
interface RadonUser {
id: string;
email: string | null;
emailVerified: boolean;
metadata: Record<string, unknown>;
createdAt: Date;
updatedAt: Date;
}Also exported: RadonIdentity, RadonSession, RadonOneTimeCode, and the Pro
entities RadonRefreshToken, RadonApiKey, RadonOrg, RadonOrgMembership,
RadonOrgInvite, plus OrgRole and DeviceInfo.
Errors
Every failure is a RadonError subclass with a stable code. Integrations map
each to an HTTP status automatically.
| Error class | code | HTTP |
|---|---|---|
RateLimitError | rate_limit_exceeded | 429 |
CodeInvalidError | code_invalid | 401 |
CodeExpiredError | code_expired | 401 |
CodeNotFoundError | code_not_found | 401 |
MaxAttemptsError | max_attempts_exceeded | 401 |
InvalidCredentialsError | invalid_credentials | 401 |
TokenInvalidError | token_invalid | 401 |
ApiKeyInvalidError | api_key_invalid | 401 |
RefreshTokenInvalidError | refresh_token_invalid | 401 |
NotAuthorizedError | not_authorized | 403 |
UserNotFoundError | user_not_found | 404 |
EmailExistsError | email_exists | 409 |
WeakPasswordError | weak_password | 400 |
OrgError | org_error | 400 |
EncryptionRequiredError | encryption_required | 400 |
ProviderNotConfiguredError | provider_not_configured | 501 |
LicenseRequiredError | license_required | 501 |
AdapterCapabilityError | adapter_capability | 501 |
EmailSendError | email_send_failed | 500 |
OAuthError | oauth_error | 400 |
import { RateLimitError } from "@radonsdk/auth";
try {
await auth.emailCode.sendCode({ email });
} catch (err) {
if (err instanceof RateLimitError) {
// err.retryAfterMs — ms until the caller can retry
}
}