Configuration
Radar (Dashboard Feature)
AI-powered bot detection with configurable providers (Vercel BotID, Cloudflare Turnstile, reCAPTCHA, hCaptcha), impossible travel detection, device fingerprinting, and rate limiting.
Preview — Radar detection rules (impossible travel, device fingerprinting) are under active development. Bot detection providers (BotID, Turnstile, reCAPTCHA, hCaptcha) are functional via dashboard configuration. APIs may change before stable release.
Banata Auth's Radar feature provides a layered defense against bots, credential stuffing, impossible travel attacks, and other automated threats. It supports multiple bot detection providers out of the box and lets you configure credentials through the dashboard — no code changes required.
How Radar Works
1. Admin configures bot detection provider + credentials in the dashboard
2. Client-side: provider widget/script injects an invisible challenge
3. User submits a sign-in, sign-up, or password reset request
4. Server-side: @banata-auth/nextjs/bot-protection verifies the challenge
5. If bot detected: request is rejected with 403
6. If human verified: request proceeds to Better Auth
7. Additional detection rules (impossible travel, fingerprinting,
rate limiting) provide defense-in-depthRadar has two layers:
- Bot detection providers — Configurable bot protection via Vercel BotID, Cloudflare Turnstile, Google reCAPTCHA, or hCaptcha. Credentials are managed through the dashboard.
- Detection rules — Configurable rules for impossible travel, device fingerprinting, rate limiting, and behavioral bot detection.
Supported Bot Detection Providers
| Provider | Fields Required | Hosting | Description |
|---|---|---|---|
| Vercel BotID | API Key | Vercel only | Invisible CAPTCHA, zero user friction |
| Cloudflare Turnstile | Site Key, Secret Key | Any | Privacy-focused CAPTCHA alternative |
| Google reCAPTCHA | Site Key, Secret Key | Any | v3 score-based detection |
| hCaptcha | Site Key, Secret Key | Any | Privacy-first CAPTCHA |
Configuring a Provider
- Navigate to Radar in the dashboard sidebar
- Click Enable protection if not already enabled
- Go to the Configuration tab
- Toggle Bot detection on
- Under Bot Detection Provider, select your provider from the dropdown
- Enter your provider credentials (API keys, site keys, secret keys)
- Click Save credentials
Credentials are stored securely in the Radar configuration and used by the @banata-auth/nextjs/bot-protection package to verify requests at runtime.
Using Bot Protection in Your App
Option 1: Config-Aware (Recommended)
Reads provider credentials from the dashboard configuration automatically:
// app/api/auth/[...all]/route.ts
import { createRouteHandler } from "@banata-auth/nextjs";
import { withBotProtection, createConfigAwareVerifier } from "@banata-auth/nextjs/bot-protection";
const handler = createRouteHandler({
convexSiteUrl: process.env.NEXT_PUBLIC_CONVEX_SITE_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 approach, changing the provider or credentials in the dashboard takes effect within 1 minute (the default config cache TTL).
Option 2: Direct Provider (Vercel BotID)
For Vercel deployments with BotID installed directly:
import { withBotProtection, createBotIdVerifier } from "@banata-auth/nextjs/bot-protection";
import { checkBotId } from "botid/server";
const verify = createBotIdVerifier(checkBotId);
export const GET = handler.GET;
export const POST = withBotProtection(handler.POST, { verify });For full API reference and all provider details, see the Bot Protection documentation.
Detection Rules
Radar provides 4 configurable detection rules that work alongside bot providers:
| Rule | Key | Default | Description |
|---|---|---|---|
| Impossible travel detection | blockImpossibleTravel | true | Flag sign-ins from geographically impossible locations within short time windows |
| Device fingerprinting | deviceFingerprinting | true | Track device characteristics to identify suspicious sign-in patterns |
| Rate limiting | rateLimiting | false | Limit authentication attempts from a single IP address or user account |
| Bot detection | botDetection | false | Use behavioral analysis to detect automated sign-in attempts |
Detection Rule Defaults
When Radar is first enabled, it ships with sensible defaults:
{
enabled: false, // Radar is disabled by default
blockImpossibleTravel: true, // On by default when Radar is enabled
deviceFingerprinting: true, // On by default when Radar is enabled
rateLimiting: false, // Off by default — enable for stricter protection
botDetection: false, // Off by default — enable for stricter protection
botProvider: null, // No bot provider selected
botProviderCredentials: {} // No credentials configured
}Radar Configuration Data Model
interface RadarConfig {
enabled: boolean; // Master toggle for Radar
blockImpossibleTravel: boolean; // Geographic anomaly detection
deviceFingerprinting: boolean; // Device characteristic tracking
rateLimiting: boolean; // Per-IP/per-user rate limits
botDetection: boolean; // Behavioral analysis
botProvider: string | null; // "botid" | "turnstile" | "recaptcha" | "hcaptcha"
botProviderCredentials: {
apiKey?: string; // Used by BotID
siteKey?: string; // Used by Turnstile, reCAPTCHA, hCaptcha
secretKey?: string; // Used by Turnstile, reCAPTCHA, hCaptcha
};
}Managing Radar via the Dashboard
- Navigate to Radar in the dashboard sidebar
Enabling Radar
The Radar page shows a hero card with feature highlights when disabled:
- Click Enable protection to turn on Radar
- The hero card switches to a green "Your application is protected" state
- Detection rules become configurable in the Configuration tab
Configuring Detection Rules
- Click the Configuration tab
- Toggle individual detection rules on or off using the switches
- Changes are saved to the backend immediately with optimistic updates
- If a save fails, the toggle reverts to its previous state
Configuring Bot Detection Provider
- In the Configuration tab, scroll to Bot Detection Provider
- Select a provider from the dropdown (BotID, Turnstile, reCAPTCHA, hCaptcha)
- A description and docs link appear for the selected provider
- Enter the required credentials (varies by provider)
- Click Save credentials
- A success toast confirms the save
Overview Tab
The Overview tab shows detection statistics (total detections, allowed, challenged, blocked) and a timeline chart. These populate with data once Radar is active in production.
When a bot provider is configured, an info banner shows which provider is active. If no provider is configured, a warning banner prompts you to set one up.
API Endpoints
The configPlugin exposes 2 Radar endpoints:
| Endpoint | Method | Description |
|---|---|---|
/api/auth/banata/config/radar/get | POST | Get current Radar configuration (including bot provider and credentials) |
/api/auth/banata/config/radar/save | POST | Update Radar configuration (partial updates supported) |
All endpoints require admin authentication.
Get Radar Config
// POST /api/auth/banata/config/radar/get
// Body: {}
// Response:
{
"enabled": true,
"blockImpossibleTravel": true,
"deviceFingerprinting": true,
"rateLimiting": false,
"botDetection": true,
"botProvider": "turnstile",
"botProviderCredentials": {
"siteKey": "0x...",
"secretKey": "0x..."
}
}Save Radar Config
// POST /api/auth/banata/config/radar/save
// Body (partial update — only include fields you want to change):
{
"botProvider": "turnstile",
"botProviderCredentials": {
"siteKey": "0x...",
"secretKey": "0x..."
}
}
// Response: the full merged RadarConfigThe save endpoint uses a merge pattern — incoming fields are spread over the existing configuration. Fields not included in the request body are left unchanged.
Database Storage
Radar configuration is stored as a singleton row in the radarConfig table:
// Simplified schema
defineTable({
configJson: v.string(), // JSON-serialized RadarConfig (including botProvider + credentials)
createdAt: v.float64(),
updatedAt: v.float64(),
})Using Radar Programmatically
Via the Dashboard API Client
import { getRadarConfig, saveRadarConfig } from "@/lib/dashboard-api";
// Get current configuration
const config = await getRadarConfig();
console.log(config.enabled); // false
console.log(config.botProvider); // null
// Enable Radar with Cloudflare Turnstile
const updated = await saveRadarConfig({
enabled: true,
botDetection: true,
botProvider: "turnstile",
botProviderCredentials: {
siteKey: "0x...",
secretKey: "0x...",
},
});Combining Radar with Rate Limiting
Radar's rate limiting detection rule works alongside Banata Auth's built-in rate limiting (configured in BanataAuthConfig). The two are complementary:
| Layer | Scope | Description |
|---|---|---|
| Built-in rate limiting | Per-endpoint | Limits requests per minute to specific auth endpoints (sign-in: 30/min, sign-up: 10/min) |
| Radar rate limiting | Per-IP/per-user | Broader detection that considers patterns across multiple endpoints and time windows |
For maximum protection, enable both.
Security Considerations
- Defense in depth — Radar provides multiple layers (bot providers, detection rules, rate limiting). Enable all layers in production.
- Provider flexibility — Not tied to a single provider. Switch providers through the dashboard without code changes.
- Credentials are server-side only — Bot provider credentials are stored in the config database and never exposed to the client-side.
- Fail-open design — If the bot detection provider is unavailable, requests are allowed through by default. Set
failOpen: falsefor stricter enforcement. - Config caching — The config-aware verifier caches radar config for 1 minute by default. Credential changes take up to 1 minute to take effect.
- Admin-only configuration — Only admins can enable/disable Radar, change detection rules, or update provider credentials.
Troubleshooting
"Bot detected. Access denied." (403)
The bot provider flagged the request as automated. This can happen if:
- The request is from an automated script without browser context
- The provider's client-side widget didn't load (check your layout/form setup)
- A browser extension is interfering with the challenge
"Detection stats showing all zeros"
Detection statistics populate once Radar is active in production and receives real traffic. In development, all requests pass through without recording statistics.
"Radar enabled but no protection"
Check that:
- A bot provider is selected in the Radar configuration
- Credentials are saved for the selected provider
- Your route handler uses
withBotProtection()with eithercreateConfigAwareVerifier()or a direct verifier - For Vercel BotID:
withBotId()is innext.config.tsand<BotIdClient>is in the layout
"Credentials not taking effect"
The config-aware verifier caches the radar config for 1 minute by default. Wait up to 1 minute after saving credentials, or set cacheTtlMs: 0 for immediate effect (not recommended in production).
What's Next
- Bot Protection Package — Full API reference for
@banata-auth/nextjs/bot-protection - Settings — Project-level configuration
- Audit Logs — Track security events and suspicious activity