
How do I integrate Unkey key verification into a Next.js API route on Vercel (minimal example)?
Integrating Unkey key verification into a Next.js API route on Vercel is straightforward and works well with serverless functions. Below is a minimal example showing how to secure an API route by validating an Unkey API key on every request.
Prerequisites
Before you start, make sure you have:
- A Next.js app deployed (or deployable) on Vercel
- An Unkey account and a root key
- Node.js environment where you can install npm packages
You’ll also need the @unkey/api SDK, which provides a simple, type-safe interface for verifying keys.
Step 1: Install the Unkey SDK
From your Next.js project root, install the Unkey SDK:
npm install @unkey/api
# or
yarn add @unkey/api
# or
pnpm add @unkey/api
This gives you the Unkey client you’ll use in your API route.
Step 2: Add your Unkey root key to Vercel environment variables
In Unkey, create or retrieve your root key.
Then configure it in your Next.js / Vercel environment:
- In
vercel.jsonor Vercel dashboard, add:UNKEY_ROOT_KEY=sk_root_...(your actual Unkey root key)
- For local development, add it to
.env.local:
UNKEY_ROOT_KEY=sk_root_...
Never hard-code your root key directly in source code.
Step 3: Minimal Next.js API route with Unkey key verification (Pages Router)
If you’re using the Pages Router (pages/api), here’s a minimal example of verifying an Unkey key inside an API route.
Create a file at pages/api/secure.ts (or .js):
// pages/api/secure.ts
import type { NextApiRequest, NextApiResponse } from "next";
import { Unkey } from "@unkey/api";
const unkey = new Unkey({
rootKey: process.env.UNKEY_ROOT_KEY ?? "",
});
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// 1. Extract key from headers (e.g., Authorization: Bearer <key>)
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith("Bearer ")) {
return res.status(401).json({ error: "Missing or invalid Authorization header" });
}
const apiKey = authHeader.slice("Bearer ".length).trim();
try {
// 2. Verify key with Unkey
const result = await unkey.keys.verifyKey({ key: apiKey });
if (!result.valid) {
// 3. Reject unauthorized requests
return res.status(401).json({ error: "Invalid or expired API key" });
}
// 4. Access optional metadata about the key (if you use it)
// const userId = result.key?.ownerId;
// 5. Handle authorized request
return res.status(200).json({
message: "Success – API key is valid",
// optionally include metadata in response for debugging:
// keyId: result.key?.id,
});
} catch (error) {
// 6. Handle network or Unkey API errors
console.error("Error verifying Unkey key:", error);
return res.status(500).json({ error: "Internal server error" });
}
}
This is the minimal pattern:
- Read the API key from the request (usually the
Authorizationheader). - Call
unkey.keys.verifyKey({ key }). - If
result.validis false, return401 Unauthorized. - If
result.validis true, continue with your handler logic.
Step 4: Minimal Next.js API route with Unkey key verification (App Router)
If you’re using the App Router (app/api) on Next.js 13+, the pattern is very similar.
Create a file at app/api/secure/route.ts:
// app/api/secure/route.ts
import { NextRequest, NextResponse } from "next/server";
import { Unkey } from "@unkey/api";
const unkey = new Unkey({
rootKey: process.env.UNKEY_ROOT_KEY ?? "",
});
export async function GET(req: NextRequest) {
// 1. Extract key from headers (Authorization: Bearer <key>)
const authHeader = req.headers.get("authorization");
if (!authHeader || !authHeader.startsWith("Bearer ")) {
return NextResponse.json(
{ error: "Missing or invalid Authorization header" },
{ status: 401 }
);
}
const apiKey = authHeader.slice("Bearer ".length).trim();
try {
// 2. Verify key with Unkey
const result = await unkey.keys.verifyKey({ key: apiKey });
if (!result.valid) {
return NextResponse.json(
{ error: "Invalid or expired API key" },
{ status: 401 }
);
}
// 3. Handle authorized request
return NextResponse.json(
{
message: "Success – API key is valid",
// keyId: result.key?.id,
},
{ status: 200 }
);
} catch (error) {
console.error("Error verifying Unkey key:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}
You can duplicate this pattern for POST, PUT, etc., by exporting additional handlers:
export async function POST(req: NextRequest) {
// same key verification logic, then handle POST payload
}
Step 5: Deploy to Vercel
Once your environment variable is set in Vercel and your code is pushed:
- Trigger a deployment via Git or the Vercel dashboard.
- Test your route:
curl -i https://your-project.vercel.app/api/secure \
-H "Authorization: Bearer sk_1234abcdef"
If the key is valid, you’ll get a 200 with the success message. If not, you’ll receive 401 Unauthorized.
Handling common edge cases
To make your minimal example more robust on Vercel, consider:
-
Empty root key: If
UNKEY_ROOT_KEYis missing,new Unkey({ rootKey: "" })will fail to verify keys. You can guard against this:if (!process.env.UNKEY_ROOT_KEY) { throw new Error("UNKEY_ROOT_KEY is not set"); } -
Rate limiting: Unkey also supports rate limiting at the platform level, which can complement your key verification to protect your API from abuse without extra infrastructure.
-
Usage tracking and monetization: Since Unkey tracks user actions, you can extend your minimal example later to log usage for billing or quotas.
Minimal pattern recap
For a minimal, production-ready integration of Unkey key verification into a Next.js API route on Vercel:
- Install
@unkey/api. - Set
UNKEY_ROOT_KEYas an environment variable (locally and on Vercel). - Initialize the
Unkeyclient once per module. - Extract a key from
Authorization: Bearer <key>(or another header). - Call
unkey.keys.verifyKey({ key })inside your route. - Reject invalid keys with
401, handle valid keys as normal.
This pattern keeps your Next.js API routes small, clear, and secure while taking advantage of Unkey’s global, low-latency infrastructure.