Sign in →
1 min read

Authentication & API Keys

How credentials work in Aforo — the two key classes, creation, rotation, and security practices for production.

Updated 2026-07-29Suggest edits

Credential types#

Aforo issues two credential classes, depending on the product type. Bearer keys (prefix sk_test_ / sk_live_) authenticate Standard API and Agentic API products. Client credentials (a afr_ client ID + a secret) authenticate AI Agent and MCP Server products.

For bearer keys, the test / live segment marks the environment. It does not change where you send events — every environment posts to the same ingest host (ingest.aforo.ai); the key you present decides which environment the event lands in.

PrefixEnvironmentUse for
sk_test_TestLocal dev, CI, integration tests
sk_live_ProductionProduction deployments only
WARNING
Never use a production key (sk_live_) in a development or CI environment. Events sent with a live key land in your production data. For a guaranteed non-billable connectivity check, post to POST /v1/ingest/test — it routes to Aforo's sandbox workspace regardless of the key you use, so nothing touches your own data. See .

Key structure

A bearer key is a 40-character opaque token: the sk_test_ / sk_live_ prefix followed by 32 hex characters (16 cryptographically random bytes, hex-encoded). Client credentials are a afr_-prefixed client ID plus a longer hex secret. In both cases Aforo stores only a SHA-256 hash of the secret — the plaintext is shown once at creation and can never be retrieved again.

key-format.txt
sk_test_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6   ← bearer key, test env
sk_live_f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1   ← bearer key, production

Bearer key structure:
  sk_        — Aforo secret-key namespace
  test_      — environment identifier (test | live)
  [32 hex]   — 16 random bytes, hex-encoded

Client credentials (AI Agent / MCP Server):
  client_id      afr_<16 hex>
  client_secret  <48 hex>        — shown once; SHA-256 hashed at rest

Creating a key#

Keys are created in the Aforo console. A key for a metered product is bound to a customer's subscription — it can't exist without one — and is revoked automatically if that subscription is cancelled.

1
Open the API Keys surface
Workspace Admin → API Keys (for named, scoped keys), or Developer Hub → Credentials (for a one-click key per environment).
2
Create the key
Choose the environment (test or live), name it, and pick the customer subscription it belongs to.
3
Copy the secret immediately
The plaintext key (or client secret) is shown exactly once. Copy it to your secrets manager now — it cannot be retrieved again.
4
Store it in a secrets manager
AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault — or a gitignored .env for local development only.
PRO TIP
Quicker path: Developer Hub → Credentials has a one-click generator for your primary test and production keys, plus a Roll button to rotate them. Use Workspace Admin when you need multiple keys or fine-grained scopes; use Developer Hub when you just need one key per environment.

Using your key#

Every Aforo API authenticates via the standard Authorization header using the Bearer scheme. There is no session, cookie, or token exchange — each request carries the key directly.

HTTP Authorization header

curl — send a usage event
curl -X POST https://ingest.aforo.ai/v1/ingest \
  -H "Authorization: Bearer sk_live_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "customerId": "cust_abc123",
    "metricName": "api_calls",
    "quantity": 1,
    "timestamp": "2026-07-29T10:00:00Z"
  }'
curl — check entitlement (read-only, served from Redis)
curl "https://ingest.aforo.ai/v1/entitlements/check?accessorId=app_abc123&productId=prod_xyz789" \
  -H "Authorization: Bearer sk_live_YOUR_KEY_HERE"

# Response (no quota is decremented — this is a read):
# {
#   "allowed": true,
#   "quotaRemaining": 8420,
#   "budgetRemaining": 42.50
# }

SDK authentication

With any Aforo SDK, pass the key at initialization. The SDK injects the Authorization header on every outbound request.

Node.js — @aforo/metering
import { AforoClient } from '@aforo/metering';

const aforo = new AforoClient({
  apiKey: process.env.AFORO_API_KEY!, // read from env — never hardcode
});
Python — aforo-metering
from aforo import AforoClient
import os

aforo = AforoClient(
    api_key=os.environ["AFORO_API_KEY"],  # read from env — never hardcode
)
INFO
Pass apiKey explicitly, as above — the client doesn't read AFORO_API_KEY from the environment for you. The framework middleware examples (Express, Django, …) simply read process.env.AFORO_API_KEY yourself and hand it to the client.

Key rotation#

Rotate a key in place with the rotate endpoint. It mints a replacement and returns it once; the old key stays valid at the gateway for a 300-second (5-minute) grace period, giving your running instances time to pick up the new one before the old stops working.

Rotate a key
# Rotate: returns the new key once. The old key keeps working at the gateway
# for 300s so you can roll it out with no gap in metering coverage.
curl -X POST https://pricing.aforo.ai/api/v1/api-keys/{keyId}/rotate \
  -H "Authorization: Bearer sk_live_YOUR_KEY_HERE"

# Response (the new secret is shown once — store it now):
# { "id": "key_xyz789", "fullToken": "sk_live_NEW_KEY_HERE", "status": "ACTIVE" }

# To revoke a key immediately instead:
curl -X DELETE https://pricing.aforo.ai/api/v1/api-keys/{keyId} \
  -H "Authorization: Bearer sk_live_YOUR_KEY_HERE"
WARNING
The one-click Roll key button in Developer Hub → Credentials revokes the old key immediately — copy the revealed key and deploy it promptly. The rotate endpoint above is the zero-downtime path: the old key survives the 300-second grace window at the gateway. A manual DELETE revokes instantly, with no grace period.

Security best practices#

API keys are long-lived credentials. These practices limit exposure if one is ever compromised.

Never commit keys to source control
Use gitignored .env files locally and your CI provider's secret store for pipelines. Pre-commit scanners like git-secrets or truffleHog catch accidental commits.
Use separate keys per environment
One sk_test_ key for development, one for CI, one sk_live_ key for production. Never share keys across environments or team members.
Rotate on team-member departure
If someone with key access leaves, rotate the keys they could reach within 24 hours. Last-used timestamps in the console help identify which are live.
Monitor for usage anomalies
Watch for a key firing far more events than usual or from an unexpected source — a signal it may be compromised.
Revoke unused keys
Any key unused for 90+ days should be revoked. Dormant keys are a liability — they can be compromised without anyone noticing.
WARNING
If you suspect a key is compromised, revoke it immediately with DELETE /api/v1/api-keys/{id} (or from the console), then rotate to a new one. A manual revoke is instant — no grace period.