Next.js Scaffold (SDK)
A Next.js App Router application using @auth-gate/nextjs for authentication. The SDK provides a catch-all route handler, composable middleware, and server-side session helpers — reducing auth setup to a few lines of configuration.
Overview
This scaffold demonstrates the SDK approach for Next.js. Instead of writing individual API route handlers for each auth endpoint, the @auth-gate/nextjs package provides:
createAuthGate()— initializes the auth client with route handlers and session helpershandlers— GET/POST catch-all handler for a[...authgate]routecreateAuthGateMiddleware()— composable middleware for route protectiongetSession()— server-side session reading
The entire auth setup consists of:
- One config file (
src/lib/auth.ts) - One catch-all route (
src/app/api/auth/[...authgate]/route.ts— 3 lines) - One middleware file (
src/middleware.ts)
Prerequisites
- Node.js 18+
- An AuthGate project with at least one provider enabled
- An API key from the AuthGate dashboard
Setup
cd apps/scaffolds/nextjs/sdk
cp .env.example .env
# Fill in your AuthGate credentials
pnpm install
pnpm dev
The dev server runs at http://localhost:3004.
Directory structure
src/
├── app/
│ ├── layout.tsx
│ ├── page.tsx # Home page
│ ├── (auth)/
│ │ ├── layout.tsx
│ │ ├── login/page.tsx
│ │ ├── signup/page.tsx
│ │ ├── forgot-password/page.tsx
│ │ └── reset-password/page.tsx
│ ├── (protected)/
│ │ ├── layout.tsx
│ │ └── dashboard/page.tsx
│ └── api/
│ └── auth/
│ └── [...authgate]/route.ts # 3 lines — delegates to SDK
├── lib/
│ └── auth.ts # SDK configuration (~42 lines)
└── middleware.ts # SDK middleware
Compared to the custom Next.js scaffold, there's no session.ts, no oauth-state.ts, no authgate.ts, and no individual email route handlers.
Key files
src/lib/auth.ts
Initializes the SDK and exports everything the app needs:
import { createAuthGate, createAuthGateMiddleware } from "@auth-gate/nextjs";
function auth() {
return createAuthGate({
apiKey: process.env.AUTHGATE_API_KEY!,
baseUrl: process.env.AUTHGATE_URL!,
appUrl,
});
}
// Route handlers for the catch-all route
export const handlers = {
GET: (...args) => auth().handlers.GET(...args),
POST: (...args) => auth().handlers.POST(...args),
};
// Server-side session reading
export async function getSession() {
return auth().session.getSession();
}
// Middleware for protecting routes
export const authMiddleware = createAuthGateMiddleware(
() => auth().client,
{ matcher: ["/dashboard/:path*"], loginPath: "/login" }
);
src/app/api/auth/[...authgate]/route.ts
The catch-all route delegates all auth requests to the SDK:
import { handlers } from "@/lib/auth";
export const { GET, POST } = handlers;
This single route handles all of:
GET /api/auth/:provider/login— OAuth redirectGET /api/auth/callback— OAuth callbackGET /api/auth/me— current userPOST /api/auth/email/signupPOST /api/auth/email/signinPOST /api/auth/email/forgot-passwordPOST /api/auth/email/reset-passwordPOST /api/auth/logout
src/middleware.ts
Uses the SDK's composable middleware:
import { authMiddleware } from "@/lib/auth";
export default async function middleware(request: NextRequest) {
const authResponse = await authMiddleware(request);
if (authResponse) return authResponse;
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard/:path*"],
};
The middleware decrypts the session cookie and redirects to /login if no valid session is found. It returns null for non-matching paths, allowing composition with other middleware.
Server-side session reading
In any Server Component or API route:
import { getSession } from "@/lib/auth";
export default async function DashboardPage() {
const user = await getSession();
// user: { id, email, name, picture, provider } | null
}
Environment variables
| Variable | Server/Client | Description |
|---|---|---|
AUTHGATE_API_KEY | Server | API key for token verification and session encryption |
AUTHGATE_URL | Server | AuthGate URL |
NEXT_PUBLIC_APP_URL | Client | Your app's URL (e.g. http://localhost:3004) |
The SDK derives both session encryption and state signing keys from the API key via HKDF-SHA256 — no additional secret is needed.