Banata

Operate Your Project

Bot Protection

Add bot detection to your Next.js auth routes using Vercel BotID, Cloudflare Turnstile, reCAPTCHA, or hCaptcha — all built into @banata-auth/nextjs.

The bot protection SDK gives you a unified way to add bot detection to your Next.js auth routes. It supports Vercel BotID, Cloudflare Turnstile, Google reCAPTCHA, and hCaptcha out of the box.

You can wire up a provider directly using environment variables, or let the SDK pull your provider configuration from the dashboard automatically at runtime.

Bot protection ships with @banata-auth/nextjs — there is nothing extra to install:

typescript
import {
  withBotProtection,
  createBotIdVerifier,
  createConfigAwareVerifier,
} from "@banata-auth/nextjs/bot-protection";

Quick Start

This approach reads your bot protection settings from the dashboard, so you can change providers or credentials without redeploying:

typescript
// app/api/auth/[...all]/route.ts
import { createRouteHandler } from "@banata-auth/nextjs";
import { withBotProtection, createConfigAwareVerifier } from "@banata-auth/nextjs/bot-protection";
 
const handler = createRouteHandler({
  apiKey: process.env.BANATA_API_KEY!,
  authUrl: process.env.BANATA_AUTH_URL,
});
 
const verify = createConfigAwareVerifier({
  configApiUrl: process.env.NEXT_PUBLIC_APP_URL + "/api/auth",
});
 
export const GET = handler.GET;
export const POST = withBotProtection(handler.POST, { verify });

With this setup, the verifier will:

  1. Fetch your Radar config from /api/auth/banata/config/radar/get
  2. Read the selected bot provider and credentials
  3. Verify incoming requests against that provider
  4. Cache the config in memory (default: 1-minute TTL)

Alternative: Direct Provider (Vercel BotID)

If you already have botid installed and want to skip dashboard configuration, you can wire up the provider directly:

typescript
// app/api/auth/[...all]/route.ts
import { createRouteHandler } from "@banata-auth/nextjs";
import { withBotProtection, createBotIdVerifier } from "@banata-auth/nextjs/bot-protection";
import { checkBotId } from "botid/server";
 
const handler = createRouteHandler({
  apiKey: process.env.BANATA_API_KEY!,
  authUrl: process.env.BANATA_AUTH_URL,
});
 
const verify = createBotIdVerifier(checkBotId);
 
export const GET = handler.GET;
export const POST = withBotProtection(handler.POST, { verify });

API Reference

withBotProtection(handler, config)

Wraps a Next.js route handler with bot protection. Only requests whose path matches a protected prefix are verified — everything else passes through untouched.

typescript
withBotProtection(handler.POST, {
  verify: async (request) => {
    return { isBot: false };
  },
  protectedPaths: ["/api/auth/sign-in", "/api/auth/sign-up"],
  failOpen: true,
  blockedMessage: "Bot detected. Access denied.",
});
OptionTypeDefaultDescription
verifyBotCheckFnRequiredFunction that checks whether a request is from a bot
protectedPathsstring[]Sign-in, sign-up, forget/reset passwordPath prefixes to protect
failOpenbooleantrueAllow requests through if verification fails
blockedMessagestring"Bot detected. Access denied."Error message returned to blocked requests

createBotIdVerifier(checkBotIdFn)

Creates a Vercel BotID verifier function:

typescript
import { checkBotId } from "botid/server";
const verify = createBotIdVerifier(checkBotId);

Returns a BotCheckFn that calls checkBotId() and maps the result. If BotID throws (for example, when you are not running on Vercel), it returns { isBot: false }.


createConfigAwareVerifier(options)

Creates a verifier that reads provider credentials from the Banata Auth config API at runtime:

typescript
const verify = createConfigAwareVerifier({
  configApiUrl: "http://localhost:3000/api/auth",
  cacheTtlMs: 60000,
  failOpen: true,
});
OptionTypeDefaultDescription
configApiUrlstringRequiredBase URL of your Banata Auth API
cacheTtlMsnumber60000 (1 min)How long to cache the Radar config
cookieHeaderstringFrom requestCookie header for authentication
failOpenbooleantrueAllow requests through on failure

Supported Providers

Vercel BotID

  • Dashboard fields: API Key
  • How it works: An invisible challenge runs automatically on Vercel deployments. The checkBotId() function verifies the challenge server-side.
  • Client-side setup: Install the botid package, add withBotId() to your next.config.ts, and render <BotIdClient> in your root layout.
  • Hosting: Vercel only.

Cloudflare Turnstile

  • Dashboard fields: Site Key, Secret Key
  • How it works: Your client sends a Turnstile token in the cf-turnstile-response or x-turnstile-token header. The server verifies it against Cloudflare's siteverify API.
  • Client-side setup: Add the Turnstile widget to your sign-in and sign-up forms.
  • Hosting: Any provider.

Google reCAPTCHA

  • Dashboard fields: Site Key, Secret Key
  • How it works: Your client sends a reCAPTCHA v3 token in the x-recaptcha-token or g-recaptcha-response header. The server verifies it and checks the score (threshold: 0.5).
  • Client-side setup: Add the reCAPTCHA v3 script to your pages.
  • Hosting: Any provider.

hCaptcha

  • Dashboard fields: Site Key, Secret Key
  • How it works: Your client sends an hCaptcha token in the x-hcaptcha-token or h-captcha-response header. The server verifies it against hCaptcha's siteverify API.
  • Client-side setup: Add the hCaptcha widget to your forms.
  • Hosting: Any provider.

Architecture

typescript
Client Request
    |
    v
[Next.js Route Handler]
    |
    v
[withBotProtection]     <-- Matches against protected paths
    |                        Calls your verify() function
    |                        Returns 403 if bot detected
    v
[Auth Processing]

The withBotProtection wrapper sits between your route handler and the auth layer. It only runs verification on the paths you configure, so non-auth routes are unaffected.


Security Considerations

  1. Fail-open by default — If the bot detection service is unavailable, requests are allowed through so legitimate users are not locked out. Set failOpen: false if you prefer stricter enforcement.
  2. Credentials stay server-side — Provider credentials (API keys, secret keys) are stored in your Radar config and never exposed to the client.
  3. Config caching — The config-aware verifier caches the Radar config for 1 minute by default. After you change credentials in the dashboard, the new values take effect within that window.
  4. Token headers — For Turnstile, reCAPTCHA, and hCaptcha, your client must send the verification token in a request header. The expected header names are standardized per provider (see the provider details above).

Next Steps

  • Radar — Enable bot detection and configure your provider credentials in the dashboard.