Cookbook: Next.js Integration
Practical guidance for integrating clients and enforcing secure access.
Cookbook: Integrate Fulan Auth in a Next.js App
This cookbook walks through a simple, production-friendly pattern for integrating a Next.js app with the Fulan Auth Service using Authorization Code + PKCE.
What you will build
- A "Sign in" button that redirects to
/authorize - A callback route that exchanges
codefor tokens via/token - A server-side session using HttpOnly cookies
- A protected page that requires a valid access token
Prerequisites
- A registered app in the Portal
- You have
client_id - You have an allowed
redirect_uri(exact match) - Your scope allowlist includes what you need (example:
openid) - Auth Service base URL (examples assume
http://localhost:8080)
Step 1: Add environment variables
Add these to your Next.js environment (example names):
| Name | Example |
|---|---|
AUTH_BASE_URL | http://localhost:8080 |
FULAN_CLIENT_ID | your-client-id |
FULAN_REDIRECT_URI | http://localhost:3000/auth/callback |
FULAN_SCOPES | openid |
Step 2: Create PKCE helper utilities
You need a code_verifier and a code_challenge:
code_verifier: random string, stored temporarily for the login attemptcode_challenge: base64url(SHA256(code_verifier))
Example helper (Node/Next.js runtime):
import crypto from "node:crypto";
function base64url(input: Buffer) {
return input
.toString("base64")
.replaceAll("+", "-")
.replaceAll("/", "_")
.replaceAll("=", "");
}
export function createPKCE() {
const verifier = base64url(crypto.randomBytes(32));
const challenge = base64url(crypto.createHash("sha256").update(verifier).digest());
return { verifier, challenge };
}Step 3: Add a login route that redirects to /authorize
Create an endpoint that:
- Generates PKCE values
- Generates a random
state - Stores
code_verifierandstatein HttpOnly cookies (short-lived) - Redirects the browser to the Auth Service
/authorizeURL
Authorize URL parameters:
response_type=codeclient_idredirect_uri(exact match)scopecode_challengecode_challenge_method=S256state
Example (route handler pseudo-code):
const authBase = process.env.AUTH_BASE_URL!;
const clientId = process.env.FULAN_CLIENT_ID!;
const redirectUri = process.env.FULAN_REDIRECT_URI!;
const scopes = process.env.FULAN_SCOPES ?? "openid";
const { verifier, challenge } = createPKCE();
const state = crypto.randomUUID();
const authorizeURL = new URL("/authorize", authBase);
authorizeURL.searchParams.set("response_type", "code");
authorizeURL.searchParams.set("client_id", clientId);
authorizeURL.searchParams.set("redirect_uri", redirectUri);
authorizeURL.searchParams.set("scope", scopes);
authorizeURL.searchParams.set("code_challenge", challenge);
authorizeURL.searchParams.set("code_challenge_method", "S256");
authorizeURL.searchParams.set("state", state);
return redirect(authorizeURL.toString());Cookie guidance:
- Store
pkce_verifierandoauth_stateas HttpOnly cookies - Use short expiration (5–10 minutes)
- Set
secure=truein production
Step 4: Add a callback route to exchange code for tokens
The Auth Service redirects back to:
<redirect_uri>?code=<auth_code>&state=<state>In the callback handler:
- Read
codeandstatefrom the query string - Read
pkce_verifierand the expectedoauth_statefrom cookies - Validate
statematches (CSRF protection) - Call
/tokenwithapplication/x-www-form-urlencoded - Store tokens in secure cookies (HttpOnly)
- Redirect to the app
Token exchange request:
POST /token
content-type: application/x-www-form-urlencoded
grant_type=authorization_code
client_id=<client_id>
code=<auth_code>
redirect_uri=<redirect_uri>
code_verifier=<code_verifier>Step 5: Create a session cookie model (recommended)
For most Next.js apps:
- Store
access_tokenin an HttpOnly cookie - Optionally store
refresh_tokenin an HttpOnly cookie - Do not store tokens in
localStorage
On each request (server side), read the cookie and:
- Validate the JWT using JWKS
- Enforce scopes from the
scopeclaim
Step 6: Protect pages or routes
Common patterns:
- Middleware redirects unauthenticated users to
/auth/login - Server Components check for the cookie and redirect if missing
Minimum check:
- If no
access_token, redirect to login
Stronger check:
- Verify JWT signature via JWKS
- Validate
iss,aud,exp - Validate scope
Step 7: Logout
Logout can be a simple cookie clear:
- Clear
access_tokenandrefresh_tokencookies - Clear PKCE/state cookies if any remain
- Redirect to home
Troubleshooting
- Redirect error:
redirect_urimust match exactly what you registered. - Token exchange fails: confirm
code_verifieris the same one that produced thecode_challenge. - Scope rejected: requested scopes must exist in the app allowlist.
- State mismatch: ensure cookies are set correctly and not blocked by cross-site policies.