ApikeeApikeeDocs
Core concepts

API keys

What a key contains, how it is checked, and what you can change after issuing one.

Anatomy

apikee_<base62 payload>.<base62 signature>

The payload holds the claims; the signature is HMAC-SHA256 over them using APIKEE_SECRET. Editing any claim invalidates the signature, so a tampered key is rejected before any database work happens.

{
  "id": "k_2f9c…",
  "tenant": "acme",
  "scopes": ["read:users", "write:orders"],
  "environment": "production",
  "expiresAt": "2027-01-01T00:00:00.000Z",
  "notBefore": null,
  "meta": { "plan": "partner" }
}

Issuing

key = apikee.create("acme", scopes=["read:users"], expires_in="90d")

expiresIn accepts a duration string ("90d", "24h", "3600s"), a timestamp, or milliseconds. Omit it for a key that never expires.

Through the platform — dashboard or REST — keys are created on a client, optionally several at once.

The raw key is returned once, at creation, and never again. The database stores only a SHA-256 hash and a 12-character display prefix. If it is lost, issue a new one.

Verification order

Server mode runs eight checks and stops at the first failure, cheapest first. Every outcome — accepted or rejected — is written to the request log with credentials redacted.

#CheckFailure
1Timestamp is sane (not in the future)401 STALE_REQUEST
2Format, HMAC signature, embedded expiry401 (400 if malformed)
3Key exists, is enabled, not expired in the database401
4Signed claims match the stored row; key belongs to this client401
5Owning client is active403
6Caller IP is in the client's allow-list403
7Request signature, when the environment has a public key401
8Template rate limits429 + Retry-After

Steps 1–2 are what your SDK does locally. Everything from step 3 needs the platform, which is why local mode cannot revoke.

What you can change later

Secret, scopes, environmentImmutable. They are signed. Issue a new key instead.
ExpiryCan only be shortened.
Name, metadataFreely editable.
Enabled / revokedToggle any time (server mode).

This is a deliberate constraint, not a limitation to work around: a key that could be widened after issuance would make the signed claims meaningless.

Limits

Active keys per client25, enforced under a row lock
Keys per request10
Clients per bulk request100
Name100 characters, no control characters
Metadata8 KiB, 5 levels deep
Expiry windowAt least 1 minute out, at most 5 years
IP rules per client100

Rotating the signing secret

The SDKs accept an array of secrets. Verification tries each, so you can rotate without downtime:

  1. Add the new secret first in the list, keep the old one after it.
  2. Deploy. New keys sign with the new secret; old keys still verify.
  3. Re-issue outstanding keys.
  4. Remove the old secret.
new Apikee({ secrets: [process.env.APIKEE_SECRET_NEW!, process.env.APIKEE_SECRET_OLD!] })

Request signing

For environments that need more than a bearer credential, set a PEM public key on the environment. The SDK then signs {clientId}|{method_path}|{timestamp} with the matching private key and sends it as x-apikee-signature (base64url). Signed requests are additionally held to a five-minute replay window.

See setPublicKey for configuring it.

On this page