Documentation

Next.js

App Router route handlers for login and callback.

Use Route Handlers for the OAuth redirect and callback so YOUR_CLIENT_SECRET stays on the server.

app/api/auth/login/route.ts
// app/api/auth/login/route.ts
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
import { createPkcePair, randomState } from "@/lib/oidc";

export async function GET() {
  const { verifier, challenge } = createPkcePair();
  const state = randomState();
  const jar = await cookies();
  jar.set("oidc_pkce", JSON.stringify({ verifier, state }), {
    httpOnly: true,
    secure: true,
    sameSite: "lax",
    maxAge: 600,
    path: "/",
  });

  const url = new URL(`${process.env.AUTH_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");

  return NextResponse.redirect(url);
}
app/api/auth/callback/route.ts
// app/api/auth/callback/route.ts
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const code = searchParams.get("code");
  const state = searchParams.get("state");
  // Validate state, load verifier from cookie, exchange code at /oauth2/token
  // Verify id_token via JWKS, create session cookie, redirect home
  return Response.redirect(new URL("/", request.url));
}
Tip
Compatible with static export only for the docs UI — your production Next.js app that performs OAuth needs a server runtime (Node, Edge, or Workers).