NamoID Docs

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_id and client_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

  • InvalidIssuerNAMOID_ISSUER must exactly match the issuer field in the discovery document (no trailing slash, correct environment subdomain).
  • redirect_uri mismatch — the URI registered on the application must be character-for-character identical to what Auth.js sends, including the /api/auth/callback/namoid suffix.
  • Wrong environmenttest credentials only work against the test issuer. A test client pointed at the live issuer is rejected at the token endpoint. See Environments.

Going further