SDKsNext.js SDK
API Routes
Protect Next.js API routes with HelloJohn — Pages Router API routes, App Router Route Handlers, and token validation patterns.
API Routes
Protect Next.js API routes using the HelloJohn SDK for both the App Router (Route Handlers) and Pages Router (API routes).
App Router: Route Handlers
Using auth()
// app/api/data/route.ts
import { auth } from "@hellojohn/nextjs/server";
import { NextResponse } from "next/server";
export async function GET() {
const { userId } = await auth();
if (!userId) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const data = await fetchUserData(userId);
return NextResponse.json(data);
}
export async function POST(request: Request) {
const { userId, orgId, orgRole } = await auth();
if (!userId) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// Role-based access
if (orgRole !== "admin") {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
const body = await request.json();
// handle POST...
return NextResponse.json({ success: true });
}Using getToken() for Downstream APIs
// app/api/proxy/route.ts
import { auth } from "@hellojohn/nextjs/server";
import { NextResponse } from "next/server";
export async function GET() {
const { getToken } = await auth();
const token = await getToken();
if (!token) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// Forward to another service using the HelloJohn access token
const upstream = await fetch("https://internal-api.example.com/data", {
headers: {
Authorization: `Bearer ${token}`,
},
});
const data = await upstream.json();
return NextResponse.json(data);
}Pages Router: API Routes
// pages/api/protected.ts
import { getAuth } from "@hellojohn/nextjs";
import type { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { userId } = getAuth(req);
if (!userId) {
return res.status(401).json({ error: "Unauthorized" });
}
return res.status(200).json({ message: "Protected data", userId });
}Verifying Bearer Tokens
For API routes called by mobile apps or third-party clients that pass Authorization: Bearer <token>:
// app/api/mobile/route.ts
import { verifyToken } from "@hellojohn/nextjs/server";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export async function GET(request: NextRequest) {
const token = request.headers.get("Authorization")?.split(" ")[1];
if (!token) {
return NextResponse.json({ error: "No token" }, { status: 401 });
}
const { payload, error } = await verifyToken(token);
if (error || !payload) {
return NextResponse.json({ error: "Invalid token" }, { status: 401 });
}
return NextResponse.json({ userId: payload.sub });
}Helper: requireAuth
Create a reusable helper for DRY protected routes:
// lib/require-auth.ts
import { auth } from "@hellojohn/nextjs/server";
import { NextResponse } from "next/server";
export async function requireAuth(
handler: (userId: string) => Promise<Response>
) {
const { userId } = await auth();
if (!userId) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
return handler(userId);
}Usage:
// app/api/orders/route.ts
import { requireAuth } from "@/lib/require-auth";
export function GET() {
return requireAuth(async (userId) => {
const orders = await db.order.findMany({ where: { userId } });
return Response.json(orders);
});
}