Exposing API routes publicly in your Next.js app can be dangerous if you don't protect them properly. If you're building something like a public-facing SaaS, internal tools, or microservices, validating API keys is a simple and effective way to protect your endpoints.
In this post, you'll learn how to secure your /api
routes using API keys with minimal code.
🔐 Step 1: Generate and store your API keys
In a real-world scenario, you'd generate an API key for each client/user and store it securely in your database. But for the purpose of this example, we'll hardcode a key.
// lib/validateApiKey.ts
export const isValidApiKey = (key?: string) => {
const validKeys = [process.env.INTERNAL_API_KEY];
return key && validKeys.includes(key);
};
Don't forget to set your INTERNAL_API_KEY
in .env.local
:
INTERNAL_API_KEY=your-secret-key
🧩 Step 2: Add middleware to protect routes
Next.js supports Edge Middleware and route handlers. For this guide, we'll use a simple pattern in an API route:
// pages/api/secure.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { isValidApiKey } from '@/lib/validateApiKey';
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const apiKey = req.headers['x-api-key'] as string;
if (!isValidApiKey(apiKey)) {
return res.status(401).json({ message: 'Unauthorized' });
}
res.status(200).json({ message: 'Access granted 🎉' });
}
You can now test it using curl or Postman:
curl -H "x-api-key: your-secret-key" http://localhost:3000/api/secure
✅ Best Practices
- Use a proper database to store keys, and hash them if possible.
- Rotate and expire keys.
- Assign scopes or permissions to different API keys.
- Monitor usage and rate limit requests per key.
🛠️ Looking for a managed solution?
If you're building a SaaS or API-first product and don't want to handle all of this manually, check out Limitly. It helps you manage API keys, enforce rate limits, and track usage — all via a simple SDK.
Happy building! 🚀
Top comments (0)