Documentation
OAuth Flow
Radiant Auth implements OAuth 2.1 Authorization Code with PKCE (S256).
Architecture
Your App (RP)
Confidential / public client
Radiant Auth
auth.rdnt.live
User
Login / consent
- App redirects to /api/auth/oauth2/authorize with PKCE (S256)
- User authenticates on Radiant Auth (email or Discord)
- Auth redirects back with ?code=…&state=…
- App exchanges code + code_verifier at /api/auth/oauth2/token
- App verifies tokens (JWKS) and creates a local session
1. Authorization request
Redirect the user's browser to the authorize endpoint. Always include PKCE and a cryptographically random state.
authorize.ts
const url = new URL("https://auth.rdnt.live/api/auth/oauth2/authorize");
url.searchParams.set("response_type", "code");
url.searchParams.set("client_id", "YOUR_CLIENT_ID");
url.searchParams.set("redirect_uri", "https://your-app.example/api/auth/callback");
url.searchParams.set("scope", "openid profile email offline_access");
url.searchParams.set("state", state);
url.searchParams.set("nonce", nonce);
url.searchParams.set("code_challenge", codeChallenge);
url.searchParams.set("code_challenge_method", "S256");
// Optional: request a JWT audience for your API
url.searchParams.set("resource", "https://your-app.example");
redirect(url.toString());Tip
Store
code_verifier, state, and nonce in an httpOnly cookie with a short TTL (for example 10 minutes) before redirecting.2. User authentication
If the user is not signed in to Radiant Auth, they are redirected to the login UI. After login (and consent when required), Radiant Auth redirects back to your redirect_uri:
callback URL
https://your-app.example/api/auth/callback?code=AUTH_CODE&state=STATEWarning
If the user denies access or an error occurs, the callback may include
error and error_description instead of code. Handle these cases explicitly.3. Token exchange
Exchange the authorization code on your backend only — never in a public browser context when you hold a client secret.
token.ts
const body = new URLSearchParams({
grant_type: "authorization_code",
code,
redirect_uri: "https://your-app.example/api/auth/callback",
client_id: "YOUR_CLIENT_ID",
client_secret: "YOUR_CLIENT_SECRET",
code_verifier: codeVerifier,
});
const res = await fetch("https://auth.rdnt.live/api/auth/oauth2/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body,
});
const tokens = await res.json();
// { access_token, token_type, expires_in, refresh_token?, scope, id_token? }4. Success response
A successful token response typically includes:
access_token— Bearer token for APIs / UserInfoid_token— JWT identity token whenopenidis usedrefresh_token— whenoffline_accesswas grantedexpires_in— access token lifetime in seconds (commonly ~3600)token_type—Bearerscope— granted scopes
PKCE checklist
- Generate a high-entropy verifier (≥ 43 characters, URL-safe)
- Challenge = Base64URL(SHA-256(verifier))
- Send
code_challenge_method=S256 - Send the original verifier on the token request
- Never log or expose the verifier to the client after exchange