Documentation menu

Access control

Allow, deny or rate-limit AI agents on your own site with the gateway’s access policy. Rules that name a platform are enforced with Web Bot Auth verification.

Last updated

Set a policy

Access control is off by default: with access unset, every agent is served as usual. Add a policy to the same GatewayConfig every adapter uses:

gateway-config.ts
import type { GatewayConfig } from '@rebilder/gateway'

export const gatewayConfig: GatewayConfig = {
  storeId: 'store_123',
  sources: { /* … */ },
  verification: { keys: myRegistry },      // required for platform-named rules
  access: {
    default: 'allow',
    rules: [
      { subject: 'chatgpt', action: 'allow' },
      { subject: 'unverified', action: 'limit', limit: { requests: 60, windowSeconds: 60 } },
      { subject: '*', action: 'allow' },
    ],
  },
}

Subjects, most specific first

  • A platform id (chatgpt, claude, gemini, perplexity and the others in Classification) matches a verified agent of that platform.
  • unverified matches any agent that presented no verifiable identity.
  • * matches every agent.
  • When nothing matches, default applies. It is allow unless you set it.

What a denied agent receives

  • A denial answers 403, and a rate limit answers 429 with Retry-After, each with a small JSON body.
  • The policy runs before any source, protocol handler or rendering, so refusing a request costs less than serving one.
  • Denied requests still emit an event on the denied path, so your reports show the effect of the policy. See Events.
  • Search crawlers are not agents: Googlebot receives your canonical HTML even under default: "deny".

Rate limits and policy updates

The rate limiter counts per process. Separate server or edge instances keep separate counts, so put a shared limiter upstream if you need one global cap.

access takes a policy or a synchronous getter; it is never fetched per request. To change the policy at runtime, fetch and verify it on your own schedule and have the getter return the latest one. Counters survive a policy swap.

gateway-config.ts
import type { AccessPolicy, GatewayConfig } from '@rebilder/gateway'

let current: AccessPolicy = BOOT_POLICY
setInterval(async () => { current = await fetchAndVerifyPolicy() }, 300_000)

export const gatewayConfig: GatewayConfig = { /* … */, access: () => current }

Validate where you edit the policy

compileAccessPolicy is exported so the screen where someone edits a policy can show which rules would be rejected, and why, before it is saved:

policy-editor.ts
import { compileAccessPolicy } from '@rebilder/gateway'

const compiled = compileAccessPolicy(draft, { verificationConfigured: true })
// Show compiled.rejected to the person editing the policy before you save it.