Next.js Integration
Add CoreSDK to a Next.js App Router project — middleware, protected API routes, and server components with user context.
Phase note. The TypeScript/Next.js SDK ships in Phase 2. The API shown is the planned surface.
Phase 2 — TypeScript SDK. The @coresdk/sdk package is not yet available. It ships in Phase 2. The code below reflects the planned API.
Next.js Integration
This guide covers integrating CoreSDK into a Next.js project using the App Router. You will configure middleware.ts to authenticate every request, protect API routes, and read user context from server components.
1. Install
npm install @coresdk/sdk
# Phase 2 — not yet published2. Initialize the SDK
Create a shared SDK instance that is reused across your server-side code.
// lib/sdk.ts
import { CoreSDK } from "@coresdk/sdk";
export const sdk = new CoreSDK({ tenant: "acme-corp" }) // Phase 2 planned API
.tenant(process.env.CORESDK_TENANT!)
.jwksUrl(process.env.CORESDK_JWKS_URL!)
.jwtAudience(process.env.CORESDK_AUDIENCE!)
.jwtIssuer(process.env.CORESDK_ISSUER!)
.build();Add the required environment variables to .env.local:
CORESDK_TENANT=acme
CORESDK_JWKS_URL=https://your-idp.com/.well-known/jwks.json
CORESDK_AUDIENCE=https://api.acme.com
CORESDK_ISSUER=https://your-idp.com/3. Middleware
middleware.ts runs on every matched request before it reaches your route handlers or server components. Verify the bearer token here and forward the resolved user identity as a request header so downstream code does not need to re-verify.
// middleware.ts
import { NextRequest, NextResponse } from "next/server";
import { sdk } from "@/lib/sdk";
export async function middleware(req: NextRequest) {
const authHeader = req.headers.get("authorization") ?? "";
const token = authHeader.startsWith("Bearer ")
? authHeader.slice(7)
: req.cookies.get("access_token")?.value;
if (!token) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const result = await sdk.verifyToken(token);
if (!result.ok) {
return NextResponse.json(
{ error: result.error.title, trace_id: result.error.traceId },
{ status: result.error.status }
);
}
// Forward verified user identity to route handlers and server components
const requestHeaders = new Headers(req.headers);
requestHeaders.set("x-user-id", result.user.id);
requestHeaders.set("x-user-email", result.user.email ?? "");
requestHeaders.set("x-user-role", result.user.role ?? "");
return NextResponse.next({ request: { headers: requestHeaders } });
}
export const config = {
matcher: ["/api/:path*", "/dashboard/:path*"],
};4. Protecting API Routes
Read the forwarded headers set by middleware. Because the token was already verified in middleware, no second verification is needed.
// app/api/documents/route.ts
import { NextRequest, NextResponse } from "next/server";
import { sdk } from "@/lib/sdk";
export async function GET(req: NextRequest) {
const userId = req.headers.get("x-user-id")!;
const userRole = req.headers.get("x-user-role")!;
// Check a policy before proceeding
const allowed = await sdk.policy.check({
principal: { id: userId, role: userRole },
action: "documents:read",
resource: { type: "document", tenantId: req.headers.get("x-tenant-id")! },
});
if (!allowed) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const documents = await fetchDocuments(userId);
return NextResponse.json({ documents });
}
export async function POST(req: NextRequest) {
const userId = req.headers.get("x-user-id")!;
const body = await req.json();
const allowed = await sdk.policy.check({
principal: { id: userId },
action: "documents:create",
resource: { type: "document" },
});
if (!allowed) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const doc = await createDocument({ ...body, ownerId: userId });
return NextResponse.json({ document: doc }, { status: 201 });
}5. Protecting Pages (Server Components)
In server components, read user context from the incoming request headers via next/headers.
// app/dashboard/page.tsx
import { headers } from "next/headers";
import { redirect } from "next/navigation";
export default async function DashboardPage() {
const headerStore = await headers();
const userId = headerStore.get("x-user-id");
// Middleware guarantees this is set for /dashboard/* routes,
// but guard defensively in case the matcher is changed.
if (!userId) {
redirect("/login");
}
const userEmail = headerStore.get("x-user-email") ?? "";
const userRole = headerStore.get("x-user-role") ?? "viewer";
return (
<main>
<h1>Dashboard</h1>
<p>Signed in as {userEmail}</p>
{userRole === "admin" && <AdminPanel />}
</main>
);
}6. TypeScript Types
CoreSDK exports types for the verified user and policy check inputs.
import type { VerifiedUser, PolicyCheckInput, PolicyCheckResult } from "@coresdk/sdk";
// Extend the verified user with your own custom claims
interface AppUser extends VerifiedUser {
orgId: string;
plan: "free" | "pro" | "enterprise";
}
// Helper to read user from request headers in API routes
export function getUserFromHeaders(req: NextRequest): VerifiedUser {
return {
id: req.headers.get("x-user-id")!,
email: req.headers.get("x-user-email") ?? undefined,
role: req.headers.get("x-user-role") ?? undefined,
};
}Summary
| Layer | What CoreSDK does |
|---|---|
middleware.ts | Verifies JWT once per request, forwards identity as headers |
| API route | Reads identity from headers, runs policy checks |
| Server component | Reads identity from headers, renders conditional UI |
| TypeScript | VerifiedUser, PolicyCheckInput, PolicyCheckResult |