Recipe: Secure API Proxy
Problem: You cannot use your OpenAI API key in client-side code (React/Vue) because anyone can steal it from the "Network" tab.
Solution: Create a backend proxy (API Route) that holds the key and forwards requests.
The Code (Next.js App Router)
typescript
// app/api/chat/route.ts
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
// 1. Force dynamic (server-side only)
export const dynamic = 'force-dynamic';
export async function POST(req: Request) {
// 2. Authentication Check (Optional but recommended)
// const session = await auth();
// if (!session) return new Response('Unauthorized', { status: 401 });
const { messages } = await req.json();
// 3. Custom Rate Limiting (Simple In-Memory)
// In production, use Redis (Upstash)
if (isRateLimited(req)) {
return new Response('Too many requests', { status: 429 });
}
// 4. Call OpenAI (Key is automatically loaded from process.env.OPENAI_API_KEY)
const result = await streamText({
model: openai('gpt-4o'),
messages,
});
// 5. Return the stream
return result.toDataStreamResponse();
}
// Simple Rate Limiter helper
const rateMap = new Map();
function isRateLimited(req: Request) {
const ip = req.headers.get('x-forwarded-for') || 'ip';
const lastTime = rateMap.get(ip) || 0;
if (Date.now() - lastTime < 1000) return true; // Max 1 req/sec
rateMap.set(ip, Date.now());
return false;
}Security Checklist
- Environment Variables:
OPENAI_API_KEYshould be in.env.localand never committed. - Usage Limits: Set a "Hard Limit" in your OpenAI dashboard (e.g., $10/month) so a bug doesn't bankrupt you.
- Authentication: Only allow logged-in users to call your API.
- Bot Protection: Use tools like Cloudflare Turnstile or Vercel Firewall.