AUTHENTICATED POST-DEPLOYMENT CONTROL
API protection for Next.js. One script tag on the frontend. One middleware on the backend. Bots blocked.
Copy the prompt below and paste it to Claude, ChatGPT, or Cursor to integrate ATTEST automatically.
npx @sekyuriti/attest login
Auto-configured
Bots blocked
One command. Auto-configures everything.
npx @sekyuriti/attest loginAuto-injected by CLI. All fetch() and XMLHttpRequest calls are automatically signed.
Script loads and hooks fetch/XHR
No code changes required
Each request is signed with HMAC-SHA256
Timestamp + fingerprint + method + URL
Headers added automatically
X-Attest-Timestamp, X-Attest-Signature, X-Attest-Fingerprint
import Script from "next/script";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<Script
src="https://sekyuriti.build/api/v2/attest/script/YOUR_KEY"
strategy="beforeInteractive"
/>
{children}
</body>
</html>
);
}Verify signatures in your API routes. Reject unsigned requests.
import { verifyAttest } from "@sekyuriti/attest";
export async function POST(request: Request) {
const result = await verifyAttest(request, {
projectId: process.env.NEXT_PUBLIC_ATTEST_KEY!,
apiKey: process.env.ATTEST_SECRET_KEY!,
});
if (!result.attested) {
return Response.json(
{ error: "Request not attested", reason: result.reason },
{ status: 403 }
);
}
// Request is verified - proceed with your logic
// result.fingerprint contains the browser fingerprint
return Response.json({ success: true });
}{
attested: true,
fingerprint: "abc123",
timestamp: 1234567890,
usage: {
used: 1234,
limit: 10000,
percent: 12
}
}{
attested: false,
reason: "Invalid signature"
}
// Possible reasons:
// - Missing ATTEST headers
// - Invalid signature
// - Timestamp expired
// - Invalid API keyProtect all API routes with one file. The recommended approach.
import { createAttestMiddleware } from "@sekyuriti/attest/middleware";
export const middleware = createAttestMiddleware({
projectId: process.env.NEXT_PUBLIC_ATTEST_KEY!,
apiKey: process.env.ATTEST_SECRET_KEY!,
});
export const config = {
matcher: "/api/:path*",
};import { createAttestMiddleware } from "@sekyuriti/attest/middleware";
export const middleware = createAttestMiddleware({
projectId: process.env.NEXT_PUBLIC_ATTEST_KEY!,
apiKey: process.env.ATTEST_SECRET_KEY!,
// Only protect specific routes
protectedRoutes: ["/api/v1/*", "/api/checkout/*"],
// Skip health check endpoint
excludeRoutes: ["/api/health"],
// Allow requests without headers during rollout
allowUnauthenticated: false,
// Custom blocked handler
onBlocked: (req, result) => {
console.log("Blocked:", result.reason);
return Response.json(
{ error: "Access denied" },
{ status: 403 }
);
},
// Log successful attestations
onAllowed: (req, result) => {
console.log("Verified:", result.fingerprint);
},
});
export const config = {
matcher: "/api/:path*",
};All exported functions and types.
Verify a single request against the ATTEST API.
async function verifyAttest(
request: Request,
config: AttestConfig
): Promise<AttestResult>
// AttestConfig
interface AttestConfig {
projectId: string;
apiKey: string;
verifyUrl?: string; // Optional, for self-hosted
}
// AttestResult
interface AttestResult {
attested: boolean;
fingerprint?: string;
timestamp?: number;
reason?: string;
warning?: string;
usage?: {
used: number;
limit: number;
percent: number;
};
}Create a reusable verifier function with config baked in.
const verify = createAttestVerifier({
projectId: process.env.NEXT_PUBLIC_ATTEST_KEY!,
apiKey: process.env.ATTEST_SECRET_KEY!,
});
// Later in your routes
const result = await verify(request);getAttestHeaders(request)Extract ATTEST headers from a request.
hasAttestHeaders(request)Check if a request has ATTEST headers.