Next.js Integration
The Surfinguard JS SDK provides utilities for protecting Next.js applications, including API route wrappers and server component helpers.
Installation
npm install @surfinguard/sdkAPI Route Protection
App Router (Route Handlers)
Wrap your route handlers with withSurfinguard to automatically check actions:
// app/api/execute/route.ts
import { Guard, withSurfinguard } from '@surfinguard/sdk';
import { NextRequest, NextResponse } from 'next/server';
const guard = await Guard.create({ mode: 'local' });
export const POST = withSurfinguard(guard, {
extractAction: (req) => ({
type: 'command',
value: req.body.command,
}),
}, async (req: NextRequest) => {
const { command } = await req.json();
// If we reach here, the command passed the security check
return NextResponse.json({ output: 'executed' });
});Manual Check in API Routes
For more control, call the guard directly in your route handler:
// app/api/chat/route.ts
import { Guard } from '@surfinguard/sdk';
import { NextRequest, NextResponse } from 'next/server';
const guard = await Guard.create({ mode: 'local' });
export async function POST(req: NextRequest) {
const { message } = await req.json();
// Check for prompt injection
const result = guard.checkText(message);
if (result.level === 'DANGER') {
return NextResponse.json(
{
error: 'Message blocked by security policy',
reasons: result.reasons,
},
{ status: 403 }
);
}
if (result.level === 'CAUTION') {
// Log but allow
console.warn('Caution-level message detected:', result.reasons);
}
// Process the message
const reply = await generateReply(message);
return NextResponse.json({ reply });
}Server Components
Use Surfinguard in React Server Components to validate data before rendering:
// app/preview/page.tsx
import { Guard } from '@surfinguard/sdk';
const guard = await Guard.create({ mode: 'local' });
export default async function PreviewPage({
searchParams,
}: {
searchParams: { url?: string };
}) {
const url = searchParams.url;
if (!url) {
return <div>No URL provided</div>;
}
const result = guard.checkUrl(url);
if (result.level === 'DANGER') {
return (
<div className="p-4 bg-red-50 border border-red-200 rounded">
<h2 className="text-red-800 font-bold">Dangerous URL Detected</h2>
<p className="text-red-600">This URL has been flagged as dangerous.</p>
<ul className="list-disc list-inside mt-2">
{result.reasons.map((reason, i) => (
<li key={i} className="text-red-600">{reason}</li>
))}
</ul>
</div>
);
}
// Safe to render preview
return <iframe src={url} className="w-full h-screen" />;
}Server Actions
Protect Server Actions with Surfinguard checks:
// app/actions.ts
'use server';
import { Guard, NotAllowedError } from '@surfinguard/sdk';
const guard = await Guard.create({ mode: 'local', policy: 'moderate' });
export async function executeQuery(query: string) {
// Check the query before execution
const result = guard.checkQuery(query);
if (result.level === 'DANGER') {
return { error: 'Query blocked', reasons: result.reasons };
}
// Execute the query
const data = await db.query(query);
return { data };
}
export async function fetchUrl(url: string) {
const result = guard.checkUrl(url);
if (result.level !== 'SAFE') {
return {
error: 'URL flagged',
level: result.level,
reasons: result.reasons,
};
}
const response = await fetch(url);
return { html: await response.text() };
}Middleware
Use Next.js middleware for request-level protection:
// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
import { Guard } from '@surfinguard/sdk';
// Note: Guard initialization in middleware runs on every request.
// For production, consider caching the guard instance.
const guard = await Guard.create({ mode: 'local' });
export function middleware(req: NextRequest) {
// Check URL parameters
const url = req.nextUrl.searchParams.get('redirect');
if (url) {
const result = guard.checkUrl(url);
if (result.level === 'DANGER') {
return NextResponse.json(
{ error: 'Dangerous redirect URL blocked' },
{ status: 403 }
);
}
}
return NextResponse.next();
}
export const config = {
matcher: '/api/:path*',
};Full Example: AI Chat Application
// app/api/chat/route.ts
import { Guard } from '@surfinguard/sdk';
import { NextRequest, NextResponse } from 'next/server';
const guard = await Guard.create({ mode: 'local' });
export async function POST(req: NextRequest) {
const { messages } = await req.json();
const lastMessage = messages[messages.length - 1];
// Check for prompt injection in user message
const textResult = guard.checkText(lastMessage.content);
if (textResult.level === 'DANGER') {
return NextResponse.json({
role: 'assistant',
content: 'I detected a potential security issue in your message and cannot process it.',
blocked: true,
reasons: textResult.reasons,
});
}
// Generate AI response
const aiResponse = await generateAIResponse(messages);
// Check any URLs in the AI response
const urlRegex = /https?:\/\/[^\s)]+/g;
const urls = aiResponse.match(urlRegex) || [];
for (const url of urls) {
const urlResult = guard.checkUrl(url);
if (urlResult.level === 'DANGER') {
return NextResponse.json({
role: 'assistant',
content: 'The AI response contained a potentially dangerous URL and has been blocked.',
blocked: true,
});
}
}
return NextResponse.json({
role: 'assistant',
content: aiResponse,
});
}