Radon
Auth Methods

OAuth (50 providers)

One generic OAuth 2.0 / OIDC engine powering 50 built-in providers — GitHub, Discord, Microsoft, Apple, and more. A Radon Pro feature.

Radon Pro

OAuth beyond Google is a Pro feature. Configure a licenseKey and call await auth.init() to unlock it. See Radon Pro. (Google sign-in is free.)

Every provider runs on one generic OAuth2/OIDC engine — there are no bespoke per-provider classes. Each provider is just a preset (endpoints + scopes + how to read the profile). Adding GitHub is a one-liner; adding a provider that isn't built in is a small object.

1. Enable one or more providers

OAuth providers live under providers.oauth, keyed by a name you choose. Pass a built-in preset id (like "github") plus your credentials.

lib/auth.ts
export const auth = new Radon({
  adapter: postgresAdapter(pool),
  session: { secret: process.env.RADON_SECRET! },
  licenseKey: process.env.RADON_LICENSE_KEY,
  providers: {
    oauth: {
      github:  { preset: "github",  clientId, clientSecret, redirectUri },
      discord: { preset: "discord", clientId, clientSecret, redirectUri },
    },
  },
});

await auth.init(); // verifies the license and unlocks Pro providers
OptionTypeDescription
presetstring | OAuthPresetBuilt-in preset id, or a custom preset.
clientIdstringOptional — falls back to an env var.
clientSecretstringOptional — falls back to an env var.
redirectUristringOptional — falls back to an env var.
scopesstring[]Override the preset's default scopes.
extraAuthParamsRecord<string,string>Extra params on the authorize URL.

You can keep credentials out of code entirely

clientId, clientSecret, and redirectUri are optional in config — if you set the matching environment variables, a provider is just github: { preset: "github" }.

2. Drive the flow

Reach a configured provider with auth.oauth(name). Unlike Google, these return an object from getAuthUrl (to support PKCE):

// 1. Build the authorize URL and redirect the user.
const { url, codeVerifier, state } = auth.oauth("github").getAuthUrl({ state: csrf });
// If `codeVerifier` is present (PKCE provider), persist it for the callback.
redirect(url);

// 2. On the callback route, exchange the code:
const { user, created, profile, tokens } = await auth.oauth("github").handleCallback({
  code: codeFromQuery,
  codeVerifier, // pass back the one from step 1, if any
});
const { token } = auth.createSessionToken(user.id);

Return shapes

getAuthUrl({ state?, scopes?, params? }){ url, codeVerifier?, state? }. handleCallback({ code, codeVerifier? }){ user, created, profile, tokens }. List configured providers with auth.oauthProvidersstring[].

The 50 built-in presets

github · gitlab · bitbucket · discord · facebook · twitter · linkedin · slack ·
spotify · twitch · reddit · tiktok · snapchat · dropbox · box · zoom · notion ·
figma · salesforce · hubspot · paypal · amazon · yahoo · epicgames · battlenet ·
roblox · patreon · strava · fitbit · coinbase · line · wechat · kakao · naver ·
vk · mailru · instagram · pinterest · dribbble · behance · zoho · digitalocean ·
microsoft · azuread · apple · wordpress · okta · auth0 · shopify · steam

Providers that need per-instance params

A few providers are multi-tenant (a Microsoft tenant, an Okta domain, a Shopify shop). Use the builder presets to bake those in:

import { microsoftPreset, shopifyPreset, oktaPreset, auth0Preset } from "@radonsdk/auth/pro/oauth";

providers: {
  oauth: {
    work:  { preset: microsoftPreset({ tenant: "your-tenant-id" }), clientId, clientSecret, redirectUri },
    store: { preset: shopifyPreset({ shop: "acme" }),               clientId, clientSecret, redirectUri },
    sso:   { preset: oktaPreset({ domain: "acme.okta.com" }),       clientId, clientSecret, redirectUri },
  },
}

Any other provider

Not in the 50? Pass your own preset object — the same shape the built-ins use. No forking required.

providers: {
  oauth: {
    acme: {
      preset: {
        id: "acme",
        name: "Acme",
        authorizationUrl: "https://acme.com/oauth/authorize",
        tokenUrl: "https://acme.com/oauth/token",
        userInfoUrl: "https://acme.com/api/me",
        defaultScopes: ["email"],
        // optional: pkce, tokenAuthStyle, scopeSeparator, useIdToken,
        //           mapProfile(raw) => ({ id, email, name, ... })
      },
      clientId, clientSecret, redirectUri,
    },
  },
}

Credentials from the environment

Every provider's clientId, clientSecret, and redirectUri fall back to environment variables, so you can keep secrets out of source entirely:

.env
RADON_GITHUB_CLIENT_ID="Iv1.xxxxxxxx"
RADON_GITHUB_CLIENT_SECRET="xxxxxxxx"
RADON_GITHUB_REDIRECT_URI="https://acme.com/api/auth/github/callback"
lib/auth.ts
// With the env vars above, the whole provider is one line:
providers: { oauth: { github: { preset: "github" } } }

The variable names are RADON_<ID>_CLIENT_ID, RADON_<ID>_CLIENT_SECRET, and RADON_<ID>_REDIRECT_URI.

The prefix comes from the preset id, not your key

<ID> is the preset's id (uppercased, non-alphanumerics → _) — not the name you give the provider in config. For built-ins named after their preset (github: { preset: "github" }) they're the same: RADON_GITHUB_*. But a renamed provider follows the preset:

oauth: { work: { preset: microsoftPreset({ tenant }) } }
// reads RADON_MICROSOFT_*  (preset id "microsoft") — NOT RADON_WORK_*

For a custom preset, the id is whatever you set as preset.id (e.g. id: "acme"RADON_ACME_*).

Explicit values in config always win over the environment.

Next steps

On this page