Quickstart: Next.js
Add Sign in with Atheron to a Next.js app with route handlers and an HTTP-only session cookie.
Sign in to see your own test client ID in the samples.
This page is for Next.js. The quickstart has every step in every language.
This uses openid-client, which reads our discovery document and handles PKCE, state and the token exchange for you.
1. Settings
Add http://localhost:3000/auth/callback as a redirect address of your test environment in the portal.
bash
ATHERON_ISSUER=https://accounts.aton-network.org
ATHERON_CLIENT_ID=test-xxxxxxxxxxxxxxxx
ATHERON_CLIENT_SECRET=ath_cs_...
ATHERON_REDIRECT_URI=http://localhost:3000/auth/callback2. Start the sign-in
ts
// app/auth/start/route.ts
import * as client from "openid-client";
import { cookies } from "next/headers";
export async function GET() {
const config = await client.discovery(new URL(process.env.ATHERON_ISSUER!), process.env.ATHERON_CLIENT_ID!, process.env.ATHERON_CLIENT_SECRET!);
const verifier = client.randomPKCECodeVerifier();
const state = client.randomState();
const nonce = client.randomNonce();
(await cookies()).set("atheron_pending", JSON.stringify({ verifier, state, nonce }), { httpOnly: true, sameSite: "lax", secure: true, path: "/", maxAge: 600 });
const url = client.buildAuthorizationUrl(config, {
redirect_uri: process.env.ATHERON_REDIRECT_URI!,
scope: "openid profile email",
code_challenge: await client.calculatePKCECodeChallenge(verifier),
code_challenge_method: "S256",
state,
nonce,
});
return Response.redirect(url.href, 303);
}3. Finish it
ts
// app/auth/callback/route.ts
import * as client from "openid-client";
import { cookies } from "next/headers";
export async function GET(request: Request) {
const jar = await cookies();
const pending = JSON.parse(jar.get("atheron_pending")?.value ?? "{}");
jar.delete("atheron_pending");
const config = await client.discovery(new URL(process.env.ATHERON_ISSUER!), process.env.ATHERON_CLIENT_ID!, process.env.ATHERON_CLIENT_SECRET!);
const tokens = await client.authorizationCodeGrant(config, new URL(request.url), {
pkceCodeVerifier: pending.verifier,
expectedState: pending.state,
expectedNonce: pending.nonce,
});
const claims = tokens.claims()!;
// claims.sub is the person's ID for your app alone, and never changes. Open your own session here.
return Response.redirect(new URL("/", request.url), 303);
}4. Ask for current details
The ID token is a snapshot from sign-in. Userinfo answers as of now, so ask it when something may have changed, such as a membership.
ts
const info = await client.fetchUserInfo(config, tokens.access_token, claims.sub);Ask Atlas
AI assistantAsk anything about Sign in with Atheron, the API or the portal. You get an answer from our docs, with links to the pages it used.