Skip to main content

Authentication

Every authenticated request carries two independent credentials:

  1. An Authorization: Bearer fb_live_... header (the API key).
  2. An X-FB-Signature header containing an HMAC-SHA-256 signature over a canonical request string.

The unauthenticated GET /governance/health endpoint is the only exception.

Getting an API key

API keys are not issued through the public API — there is no Bearer-key or HMAC path to mint one. To get a key you must:

  1. Sign up for a FlowBeacon account and sign in to the console.
  2. Make sure you hold the admin or owner role in your organization. Key creation, rotation, and revocation are restricted to those roles; a member without them receives 403 Admin or owner role required.
  3. Create the key from the console (or call the session-authenticated POST /api/v1/keys, which relies on your browser's NextAuth session cookie — it does not accept a Bearer key or HMAC signature).

The raw key is shown exactly once on creation and is never retrievable afterward — store it securely. These admin endpoints live at /api/v1/keys, outside /api/public/v1/*. See Rotating and revoking keys.

1. Bearer API key

Authorization: Bearer fb_live_<48 hex chars>

Keys are validated against a SHA-256 hash stored server-side; the raw value is never retrievable after creation. Each request also checks that the key is active, not revoked, and not past expires_at.

Key format

PartValue
Prefixfb_live_
Body48 lowercase hexadecimal characters (24 random bytes)
Total length56 characters
Displayable prefixFirst 12 characters (fb_live_xxxx) are safe to log or show in UI

2. HMAC request signing

Every authenticated request must carry X-FB-Signature. Requests without it return HTTP 403 Missing request signature. Malformed or stale signatures return HTTP 403 Invalid request signature.

Canonical signing string

message = "{timestamp}.{HTTP_METHOD}.{request_path}.{raw_request_body}"
  • timestamp — current Unix time in seconds.
  • HTTP_METHOD — uppercase, for example POST or GET.
  • request_path — the path component only, including the leading /api/public/v1/.... No query string.
  • raw_request_body — the exact bytes sent in the request body, or empty string for bodyless requests.

Algorithm and header

  • Signing key: the raw API key string itself.
  • Algorithm: HMAC-SHA-256, lowercase hex output.
  • Header format: X-FB-Signature: t=<unix>,v1=<hex>
X-FB-Signature: t=1714564800,v1=9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

Tolerance window

The timestamp must be within 300 seconds of server time. Requests outside this window are rejected with 403 Invalid request signature. This prevents replay attacks.

Reference implementations

import crypto from 'node:crypto';

export function signRequest({
method,
path, // e.g. '/api/public/v1/evaluate'
rawBody, // exact bytes you will send
apiKey,
}: {
method: string;
path: string;
rawBody: string;
apiKey: string;
}): string {
const timestamp = Math.floor(Date.now() / 1000);
const message = `${timestamp}.${method.toUpperCase()}.${path}.${rawBody}`;
const signature = crypto.createHmac('sha256', apiKey).update(message).digest('hex');
return `t=${timestamp},v1=${signature}`;
}

The server uses constant-time comparison. Signature mismatches return HTTP 403 Invalid request signature. A missing header returns HTTP 403 Missing request signature.

:::tip Sign the bytes you send JSON.stringify and Python json.dumps are not byte-stable across runtimes. Always sign the exact bytes you will send — serialise once, sign that string, transmit that string. :::

3. IP allowlisting

Each API key supports an optional list of allowed source IPs (IPv4 or IPv6). When set, requests from any other IP return HTTP 403 IP address not allowed. The client IP is taken from the first entry of X-Forwarded-For when present, otherwise the direct peer address.

Leaving the allowlist empty disables this check for the key. See the IP allowlisting guide.

4. Transport security

  • Only HTTPS is accepted in production.
  • TLS 1.2 or higher is required.
  • Browser-origin requests are blocked by default; this API is intended for server-to-server usage. Partners requiring browser access during development should contact support.

5. Key rotation

Use the web console or POST /keys/{id}/rotate to rotate a key. Rotation creates a replacement with identical configuration and schedules the old key to expire after a configurable grace period (default 24h, max 168h). During the grace period both keys work, allowing zero-downtime deploys. See Rotating and revoking keys.

6. Webhook signatures (different signing key)

Webhook deliveries use the subscription's signing_secret, not the API key, and the canonical string is shorter: "{timestamp}.{raw_body}" (no method, no path — the receiver controls the URL). See Handle webhooks.

Next steps