Documentation

Express

Classic Node.js Express routes for OAuth login and callback.

server.ts
import express from "express";
import { createPkcePair } from "./pkce";

const app = express();
const ISSUER = process.env.AUTH_ISSUER!; // https://auth.rdnt.live/api/auth

app.get("/auth/login", (req, res) => {
  const { verifier, challenge } = createPkcePair();
  const state = crypto.randomUUID();
  req.session.oidc = { verifier, state };

  const url = new URL(`${ISSUER}/oauth2/authorize`);
  url.searchParams.set("response_type", "code");
  url.searchParams.set("client_id", process.env.AUTH_CLIENT_ID!); // YOUR_CLIENT_ID
  url.searchParams.set("redirect_uri", process.env.AUTH_REDIRECT_URI!);
  url.searchParams.set("scope", "openid profile email offline_access");
  url.searchParams.set("state", state);
  url.searchParams.set("code_challenge", challenge);
  url.searchParams.set("code_challenge_method", "S256");
  res.redirect(url.toString());
});

app.get("/auth/callback", async (req, res) => {
  const { code, state } = req.query;
  if (state !== req.session.oidc?.state) return res.status(400).send("Invalid state");

  const body = new URLSearchParams({
    grant_type: "authorization_code",
    code: String(code),
    redirect_uri: process.env.AUTH_REDIRECT_URI!,
    client_id: process.env.AUTH_CLIENT_ID!,
    client_secret: process.env.AUTH_CLIENT_SECRET!, // YOUR_CLIENT_SECRET
    code_verifier: req.session.oidc.verifier,
  });

  const tokenRes = await fetch(`${ISSUER}/oauth2/token`, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body,
  });
  const tokens = await tokenRes.json();
  // verify id_token, create session
  res.redirect("/");
});