Next.js quickstart
This is the fastest standards-based way to see NamoID end to end. It uses
Next.js App Router and Auth.js v5 (NextAuth) as the OIDC client. If you
want NamoID's route-handler SDK to manage transaction cookies, callback
validation, token exchange, and ID-token verification for you, start with
@namoidhq/nextjs instead.
Prerequisites
- A NamoID project with an application (see Getting started)
- The application's
client_idandclient_secret - Your project's issuer URL:
https://<slug>.id.namoid.in
When you create the application, set its redirect URI to:
http://localhost:3001/api/auth/callback/namoid
1. Environment variables
# .env.local
NAMOID_ISSUER=https://<slug>.id.namoid.in
NAMOID_CLIENT_ID=idpc_test_…
NAMOID_CLIENT_SECRET=idps_test_…
AUTH_SECRET=… # openssl rand -base64 32
AUTH_URL=http://localhost:3001
2. Configure Auth.js
// auth.ts
import NextAuth from "next-auth";
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
{
id: "namoid",
name: "NamoID",
type: "oidc",
issuer: process.env.NAMOID_ISSUER,
clientId: process.env.NAMOID_CLIENT_ID,
clientSecret: process.env.NAMOID_CLIENT_SECRET,
authorization: { params: { scope: "openid profile email" } },
},
],
callbacks: {
jwt({ token, profile }) {
if (profile?.sub) token.sub = profile.sub;
return token;
},
session({ session, token }) {
if (session.user && token.sub) session.user.id = token.sub;
return session;
},
},
});
Auth.js reads the discovery document from NAMOID_ISSUER and enables PKCE
automatically — you never reference /authorize, /token, or /jwks.json
directly.
3. Mount the route handlers
// app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/auth";
export const { GET, POST } = handlers;
4. Add a sign-in button
// app/page.tsx
import { signIn } from "@/auth";
export default function Home() {
return (
<form action={async () => { "use server"; await signIn("namoid"); }}>
<button type="submit">Sign in with NamoID</button>
</form>
);
}
5. Protect a route
// app/dashboard/page.tsx
import { auth } from "@/auth";
import { redirect } from "next/navigation";
export default async function Dashboard() {
const session = await auth();
if (!session) redirect("/");
return <pre>{JSON.stringify(session, null, 2)}</pre>;
}
Run next dev -p 3001, click Sign in with NamoID, complete the hosted
login, and you'll land back on /dashboard with a session.
Troubleshooting
InvalidIssuer—NAMOID_ISSUERmust exactly match theissuerfield in the discovery document (no trailing slash, correct environment subdomain).redirect_urimismatch — the URI registered on the application must be character-for-character identical to what Auth.js sends, including the/api/auth/callback/namoidsuffix.- Wrong environment —
testcredentials only work against the test issuer. Atestclient pointed at theliveissuer is rejected at the token endpoint. See Environments.
Going further
- Use the
@namoidhq/reactcomponents instead of hand-rolling buttons. - Use
@namoidhq/nextjsif you want NamoID's SDK to own the OAuth callback validation and token exchange. - Read Tokens & claims to validate and use the ID token.