Next.js Scaffold (Custom)
A Next.js App Router application with custom OAuth and email authentication using API routes and middleware. This scaffold implements all auth flows from scratch — no SDK required.
Overview
This scaffold shows how to integrate AuthGate into a Next.js app using the App Router. It uses the same auth patterns as the React scaffold but adapted for Next.js conventions: API route handlers, middleware-based route protection, and the async cookies() API.
What's included:
- Next.js 16 with App Router
- API route handlers for OAuth callback and email auth
- Middleware-based protection for
/dashboardroutes - HMAC-signed session cookies with timing-safe comparison
- Nonce-based OAuth state validation
- Route groups for
(auth)and(protected)layouts - Environment validation with
@t3-oss/env-nextjs
Prerequisites
- Node.js 18+
- An AuthGate project with at least one provider enabled
- An API key from the AuthGate dashboard
- A registered callback URL pointing to
/api/auth/callback
Setup
cd apps/scaffolds/nextjs/custom
cp .env.example .env
# Fill in your AuthGate credentials
pnpm install
pnpm dev
The dev server runs at http://localhost:3002.
Directory structure
src/
├── app/
│ ├── layout.tsx
│ ├── page.tsx # Home page
│ ├── (auth)/
│ │ ├── layout.tsx # Auth pages layout
│ │ ├── login/page.tsx
│ │ ├── signup/page.tsx
│ │ ├── forgot-password/page.tsx
│ │ └── reset-password/page.tsx
│ ├── (protected)/
│ │ └── dashboard/page.tsx
│ └── api/
│ └── auth/
│ ├── callback/route.ts # OAuth callback handler
│ └── email/
│ ├── signup/route.ts
│ ├── signin/route.ts
│ ├── forgot-password/route.ts
│ └── reset-password/route.ts
├── lib/
│ ├── session.ts # HMAC-signed cookie helpers
│ ├── oauth-state.ts # State creation + verification
│ └── authgate.ts # Token verification
├── env.ts # t3-oss env validation
└── middleware.ts # Route protection
Key files
src/lib/session.ts
Manages HMAC-signed session cookies using the Next.js cookies() API:
getSession()— reads and verifies the session cookie, returns the user ornullsetSession(user)— signs and sets the session cookie (7-day expiry)clearSession()— deletes the session cookie
The session format is JSON.signature where the signature is HMAC-SHA256 with timing-safe comparison on verification.
src/lib/oauth-state.ts
Creates and verifies HMAC-signed OAuth state parameters:
createState(nonce)— returnsnonce.timestamp.hmac_signatureverifyState(state, nonce)— checks nonce match, 10-minute TTL, and HMAC signature
Both functions use timing-safe comparison to prevent timing attacks.
src/app/api/auth/callback/route.ts
The OAuth callback handler:
- Reads
tokenandstatefrom query params - Retrieves the stored nonce from cookie
- Verifies state (nonce + timestamp + HMAC)
- Verifies the JWT with AuthGate's
/api/v1/token/verify - Sets the session cookie and redirects to
/dashboard
src/middleware.ts
Protects /dashboard routes by checking for a valid session cookie. Redirects unauthenticated users to /login.
Differences from the React scaffold
| Aspect | React (Hono) | Next.js |
|---|---|---|
| Server | Hono + Node.js | Next.js API routes |
| Route protection | React component (AuthGuard) | Next.js middleware |
| Cookie API | hono/cookie helpers | next/headers cookies() |
| Env validation | Manual (Zod) | @t3-oss/env-nextjs |
| Route groups | React Router | (auth) / (protected) |
Environment variables
| Variable | Server/Client | Description |
|---|---|---|
AUTHGATE_URL | Server | AuthGate API base URL |
AUTHGATE_API_KEY | Server | API key for token verification |
STATE_SECRET | Server | Min 32 characters, used for HMAC signing |
NEXT_PUBLIC_APP_URL | Client | Your app's URL (e.g. http://localhost:3002) |