Skip to content
UsageRail
How it works / API keys

API keys

Keys issued by UsageRail look like acme_live_PRjuGinc... and are checked inside your API, against a copy of your app's keys that every SDK instance keeps in memory. Checking a key that's already in the local copy adds no network call.

text
acme_live_PRjuGincAHq68hICyifjdBmNASZ1Fw9mwPOgy8pt0EJiLE

Format

Every key has five parts:

PartIn the exampleWhat it is
PrefixacmeSet per app, 2 to 10 lowercase letters or digits.
Modelivelive or test, from the app's mode.
Key IDPRjuGinc8 characters. Names the key in the console and in logs; it isn't secret.
SecretThe next 32 charactersRandom.
ChecksumThe last 6 charactersCRC-32 of everything before it, in base62.

After the prefix and mode, every character is base62: digits and upper and lower case letters. The checksum lets the SDK refuse a mistyped or made-up key without looking anything up. The API key generator makes and checks keys in the same format.

Where keys come from

  • You create them on a customer's page in the console.
  • Your backend creates them through the server API.
  • Your customers create their own in your developer portal, once it opens.

Each customer can have 10 active keys at once by default; change it to anything from 1 to 50 under Settings > Keys per customer. An app can have up to 100,000 active keys. The full key is shown once, when it's created. UsageRail keeps only its SHA-256 hash, so a lost key can't be recovered, only replaced.

How a key is checked

For each request, in this order:

  1. The format and checksum. If either is wrong, the request gets a 401 straight away.
  2. The key ID is looked up in the local copy, and the key's hash is compared with the stored one in constant time.
  3. The key's status and expiry time.
  4. The customer the key belongs to. A suspended customer gets a 403; otherwise the request goes on to the rate limit and the quota.

The local copy syncs every 15 seconds. A key created since the last sync isn't in it yet, so the SDK asks UsageRail about that key, waits at most 300 ms, and remembers the answer until the next sync. A key that UsageRail says is invalid is remembered as invalid for 60 seconds.

Each process asks about at most 20 unknown keys per second and refuses the rest with a 401. That way a flood of random keys sent to your API doesn't turn into a flood of calls to UsageRail. A process that hasn't finished its first sync doesn't know any key yet, so until then the rest are handled as if UsageRail were unreachable: by default they get a 503, and the client can retry.

Rotating a key

A rotation creates a new key and gives the old one an expiry time, so your customer can roll out the new key before the old one stops working. In the portal, the customer picks how long the old key keeps working: anything from 1 hour to 30 days, 24 hours by default. The old key still counts toward the customer's limit until it expires.

Expiry is checked with your server's clock. The SDK treats a key as expired 30 seconds before its expiry time, to allow for clocks that are slightly off.

Revoking a key

A revoked key stops working everywhere within about 20 seconds: it changes in UsageRail at once, and every running SDK picks it up at its next sync. Revoke keys in the console, in the portal, or with DELETE /v1/keys/{key_id} in the server API.

Suspending a customer in the console also revokes their keys, so their requests get a 401 from then on.

Where the key list is kept

The SDK keeps key IDs, hashes, owners, status and expiry times in memory, never the keys themselves. A long-running process also saves the list to a private folder in the system temp directory, so after a restart it can check keys before its first sync. A saved list older than 24 hours is ignored.

When UsageRail is unreachable

Keys the SDK already knows keep working from its local copy. Keys it doesn't know depend on two settings, under Settings > When UsageRail can't be reached:

SituationKeys in the local copyKeys not in it
Synced within the last 10 minutesChecked locallyAsked about; if UsageRail doesn't answer, the unknown-key setting applies
No sync for over 10 minutes, set to Keep checking new keys remotely (default)Checked locallySame as above
No sync for over 10 minutes, set to Only accept keys in the local copyChecked locallyRefused with a 401, without asking
No local copy, or one over 24 hours oldNot usedAsked about; if UsageRail doesn't answer, the unknown-key setting applies

The unknown-key setting has two choices:

  • Refuse it (503), the default. The request gets a 503 auth_unavailable. Safer: nobody gets in with a key you can't verify, but a key created during the outage can't be used until UsageRail is back.
  • Let it through. The request is served as anonymous: it isn't rate limited or counted against a quota, and it's never billed.

To set them in code instead, pass onKeyStoreUnavailable: "deny" or "allow", and staleKeySnapshot: "allow" or "deny", to the middleware. Values passed in code win over the console.