Back to BlogSecurity & Compliance

API Key Management for Your SaaS: Issue, Scope, Rotate and Revoke

Rupak Amin

Founder & Lead Engineer, RAITHub

9 min read

RAITHub ships and tests production software. See QA as a Service or talk to us.

Manage SaaS API keys as you would any long-lived credential: give each key a readable prefix, store only its hash, bind it to exactly one tenant and a set of scopes, show the full key once and never again, let a customer create several keys so they can rotate one without downtime, revoke instantly, and record when each key was last used so dead keys can be found and removed.

This is the self-service side of the keys a customer uses to call your API. For the full public-API contract around them, see the public API design guide. This is engineering guidance written to OWASP-level practice, not a certified penetration test; where you need one, see the security testing service. If you would rather have it built and tested for you, see how RAITHub would build this below.

Why does an API key need managing, not just generating?

Because an API key is a password that lives in a customer's code for years, pasted into scripts, CI pipelines and config files by people who may have left. It leaks more easily than a login password and it does not expire on its own. The OWASP API Security Top 10 (2023) lists broken authentication as API2, and key lifecycle, how keys are issued, scoped, rotated and revoked, is where that failure usually starts.

CapabilityWhy it mattersWhat breaks without it
Hashed storageA leaked database reveals no usable keysEvery customer key is compromised at once
ScopesA key does only what the integration needsA read widget key can also delete data
Several keys per tenantRotate one integration without touching othersRotation means downtime, so it never happens
Instant revocationA leaked key is cut off immediatelyA known-leaked key keeps working
Last-used trackingDead keys can be found and removedForgotten keys stay valid forever

How should an API key be generated and stored?

Generate at least 256 bits of randomness, add a readable prefix, show the whole key once, and store only its SHA-256 hash with a short hint for the UI. Because the key is long and random, a fast hash is enough; there is nothing to guess from a dictionary, unlike a human password.

import { randomBytes, createHash } from 'node:crypto'

const PREFIX = { live: 'acme_live_', test: 'acme_test_' } as const
const sha256 = (v: string) => createHash('sha256').update(v).digest('hex')

// Returns the full key ONCE, for display. Persist only hash and hint.
export function generateApiKey(env: 'live' | 'test') {
  const secret = randomBytes(32).toString('base64url') // 256 bits of entropy
  const key = PREFIX[env] + secret
  return { key, hash: sha256(key), hint: key.slice(-4) }
}

The prefix is not decoration. GitHub explained in its post on new authentication token formats that an identifiable prefix lets leaked keys be detected by secret scanners, and a live or test marker tells your support team at a glance which environment a key belongs to.

How do you scope a key and bind it to one tenant?

Store the tenant and the scopes with each key, and resolve them on every request so the key's reach is decided server-side, not by whatever the caller claims. A read-only key must fail on every write. The scopes can mirror your permission codes, which keeps the API consistent with your roles, as in the SaaS authorization and RBAC design guide.

CREATE TABLE api_keys (
  id           uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  tenant_id    uuid NOT NULL REFERENCES tenants(id),
  name         text NOT NULL,          -- 'Zapier sync', chosen by the customer
  key_hash     text NOT NULL UNIQUE,   -- sha256 of the full key
  hint         text NOT NULL,          -- last 4 characters, for the UI
  scopes       text[] NOT NULL,        -- {invoices:read, customers:write}
  created_by   uuid NOT NULL,
  last_used_at timestamptz,
  expires_at   timestamptz,
  revoked_at   timestamptz
);

-- Authenticate: one indexed read on the hash, then tenant and scopes drive the request.
-- SELECT tenant_id, scopes FROM api_keys
--   WHERE key_hash = $1 AND revoked_at IS NULL
--     AND (expires_at IS NULL OR expires_at > now());

Once the key resolves to a tenant, every query in that request is filtered by that tenant. The most common API flaw is still reading another customer's record by changing an ID, covered in users can see another tenant's data. Let customers name each key, so "Zapier sync" is distinguishable from "data warehouse" when one needs revoking.

How do customers rotate a key without downtime?

Because a tenant can hold several keys at once, rotation is: create a new key, deploy it in the integration, confirm it works, then revoke the old one. The two keys overlap, so there is no moment where calls fail. This only works if you let customers create multiple named keys; a single key per account forces a break at every rotation, which is why single-key designs never get rotated.

// Rotation is three self-service steps, no downtime:
// 1. POST /api-keys            -> new key shown once
// 2. (customer updates their integration, verifies calls succeed)
// 3. DELETE /api-keys/{oldId}  -> sets revoked_at = now(), old key stops instantly

Revocation must take effect immediately: set revoked_at and have the authentication check reject any revoked key on the next request. Offer optional expiry for keys that should be short-lived, such as one issued for a one-off migration.

How do you help customers find keys they have forgotten?

Record last_used_at on each successful call (a cheap periodic update, not a write on every request), and show it in the UI. A key last used six months ago is probably safe to revoke, and a key that has never been used is often a leaked or abandoned one. Surfacing this turns key hygiene into something the customer can do themselves, rather than a mystery nobody dares touch. Record creation, rotation and revocation in the audit log, as in the SaaS audit log design guide, so a security review can see the full history of a key.

Do-it-yourself estimate: 1 week for hashed, prefixed, scoped keys with a self-service screen to create, name, rotate and revoke them, if your API is already tenant-safe. The main risks are storing keys in plain text, a single key per account that blocks rotation, and revocation that does not take effect until a cache expires.

Buy, build or hire?

OptionExamplesChoose this whenWatch out for
An API gateway / management productA hosted gateway with key issuance and quotasYou want keys, quotas and a developer portal in front of an existing APIThe gateway checks the key, not whether the record belongs to the caller's tenant
An auth provider's machine tokensA provider that issues service credentialsYou already use them for login and want tokens tooScopes and self-service rotation UX may still be yours to build
Custom build in your back endThe design in this guideKeys must map to your tenancy, scopes and audit logYou own hashing, rotation, revocation and last-used tracking
Hire a team to build itRAITHub or another studioCustomers are integrating now and keys must be safe and testableGet the scope and revocation tests in the handover

How do you test API key management?

  • Hashing: assert the plain key is never stored or logged, only its hash and hint.
  • Scopes: a read-only key must fail on every write endpoint; a write key must not exceed its scopes.
  • Tenant binding: a key for tenant A must never return tenant B's data, even with B's IDs.
  • Revocation: revoke a key and assert the very next request is rejected.
  • Rotation: run two overlapping keys and assert both work until the old one is revoked.

How RAITHub would build this

  • Key model: prefixed, hashed, tenant-bound keys with scopes that mirror your permissions, and optional expiry.
  • Self-service: a screen to create, name, rotate and revoke keys, with last-used shown so dead keys are visible.
  • Lifecycle: instant revocation, overlapping keys for zero-downtime rotation, and every change written to the audit log.
  • Tests: hashing, scope, tenant-binding, revocation and rotation tests in CI.

Timeline: key management inside a new SaaS build fits the 4–6 week fixed scope; added to an existing API it is a bounded piece in the 6–12 week backend range. You receive: authentication and isolation tests in CI, handover docs and runbooks, and full IP under NDA. RAITHub is not SOC 2 or ISO 27001 certified; it builds the controls and signs DPAs and SCCs.

Next step: a free 15-minute technical audit, then a written fixed quote. See the SaaS development service or the security testing service, compare the related 2FA build guide, and book the audit.

Frequently asked questions

How should SaaS API keys be stored?

Store only a SHA-256 hash of each key plus a short hint for display, and show the full key once. Because the key is long and random, a fast hash is enough, and a leaked database then reveals no usable keys.

Should a customer have one API key or several?

Several, each named and scoped. Multiple keys let a customer rotate one integration without breaking the others. A single key per account forces downtime at every rotation, which is why those keys are almost never rotated.

How do customers rotate a key without downtime?

Create a new key, deploy it, confirm it works, then revoke the old one. The two keys overlap, so no call fails during the switch. This requires support for multiple keys per tenant and instant revocation.

What do API key scopes do?

Scopes limit what a key can do, such as read invoices but not delete customers, enforced server-side on every request. A read-only widget key with a leak then cannot modify data, which narrows the blast radius of any exposure.

How do I find API keys that are no longer used?

Record a last-used timestamp on each key (a periodic update, not a write per request) and show it in the UI. A key unused for months is usually safe to revoke, and one never used is often leaked or abandoned.

API keyskey managementsecretsauthenticationSaaSsecurityTypeScript

Ready to discuss your project?

Book a free 15-minute technical audit with our engineering team.