# Next.js The Next.js plugin simplifies integrating ALTCHA into your application. It provides handlers and middleware for challenge generation and verification. ## Handlers * `challengeHandler` — Generates a new challenge. Configure this endpoint as the widget’s `challenge` URL. * `verifyHandler` — Optional handler for server-side verification. Useful when external services need to verify a payload. ## Middleware The middleware automatically handles verification during requests. Features: * Validates the payload from the request body or a configured cookie. * Sets `req.__altcha: AltchaResult`, which includes the challenge data and verification result. Options: * `throwOnFailure: boolean` — Whether to throw an error on verification failure (default: `true`). ## Store The `store` marks challenges as used to prevent reuse. See [`/docs/store.md`](/docs/store.md) for details. ## Remote verification (Sentinel) Pass a `verifyServer` option to verify Sentinel-issued payloads remotely via Sentinel's `/v1/verify/signature` API instead of locally with `hmacSignatureSecret`. See [`/docs/server-signatures.md#remote-verification-sentinel-api`](/docs/server-signatures.md#remote-verification-sentinel-api) for details. ## Usage ### 1. Create the altcha instance File: `lib/altcha.ts` ```ts import { create, deriveHmacKeySecret, randomInt, CappedMap } from 'altcha-lib/frameworks/nextjs'; import { deriveKey } from 'altcha-lib/algorithms/pbkdf2'; // Define your HMAC secret const HMAC_SECRET = 'secret.key'; export const altcha = create({ // Verification HMAC secrets hmacSignatureSecret: HMAC_SECRET, hmacKeySignatureSecret: await deriveHmacKeySecret(HMAC_SECRET), // Adjust challenge parameters createChallengeParameters: () => { return { algorithm: 'PBKDF2/SHA-256', // Adjust cost and counter depending on the algorithm cost: 5_000, counter: randomInt(5_000, 10_000), expiresAt: new Date(Date.now() + 600_000), // 10 minutes }; }, // Key derivation function for the selected algorithm deriveKey, // Use a cookie instead of form data to send the payload setCookie: { name: 'altcha', path: '/', }, // In distributed environments, use Redis or another shared store store: new CappedMap({ maxSize: 1_000, }), }); ``` ### 2. Challenge endpoint File: `app/altcha/challenge/route.ts` ```ts import { altcha } from '@/src/altcha'; export const GET = altcha.challengeHandler; ``` ### 3. Standalone verify endpoint File: `app/altcha/verify/route.ts` ```ts import { altcha } from '@/src/altcha'; export const POST = altcha.verifyHandler; ``` ### 4a. Protect a route handler with withMiddleware File: `app/protected/route.ts` ```ts import { NextResponse } from 'next/server'; import { altcha } from '@/src/altcha'; import type { AltchaResult } from '@/src/altcha'; export const POST = altcha.withMiddleware(async (req: Request) => { return NextResponse.json({ altcha: (req as { __altcha: AltchaResult }).__altcha, }); }); ``` ### 4b. Use middleware in Next.js middleware.ts File: `middleware.ts` ```ts import { NextRequest, NextResponse } from 'next/server'; import { altcha } from '@/src/altcha'; export async function middleware(req: NextRequest) { if (req.method === 'POST') { const result = await altcha.middleware(req); if (result instanceof Response) { return result; // verification failed — 403 response } } return NextResponse.next(); } export const config = { matcher: ['/api/protected/:path*'], }; ```