Back to blog
engineering

Why our public API uses HMAC signing instead of JWTs

A short and opinionated piece on why we picked HMAC + timestamp for the public license API.

KeyStack team

Founding team · May 10, 2026

Why our public API uses HMAC signing, not JWTs

If you skim the KeyStack docs the first thing that jumps out is the public API doesn't use plain Authorization: Bearer <token>. Instead, every request must include a timestamp and an HMAC-SHA256 signature.

Why?

1. JWTs leak too easily

A bearer token in the URL bar, in a log file, in an error report, in a third-party SDK — that's a full compromise. HMAC signatures are computed per-request, so even if the signature leaks, it's only valid for ~5 minutes against the exact body it was generated for.

2. Replay protection comes free

Pair the timestamp with a Redis nonce store and you have replay protection without inventing a separate nonce scheme. We give you 5 minutes of clock skew tolerance and remember every signature for 10 minutes. Send the same request twice — 409 api/timestamp-replay.

3. Rotation without downtime

A leaked API secret can be rotated in seconds. Old clients keep working until you flip the kill switch; new clients pick up the new secret on next request. JWTs require a longer dance with refresh tokens and denylists.

4. It costs you ~5 lines of code

const sig = crypto
  .createHmac('sha256', secret)
  .update(`${ts}.${body}`)
  .digest('hex');

That's it. Compared to "set up JWT issuer, rotate keys, handle exp, handle nbf, distribute JWKS endpoint" the operational cost is trivial.

When we do use JWTs

For dashboard sessions where:

  • The client is a browser (so timestamp skew is a real headache).
  • The traffic is one-tenant-at-a-time (so rotation cost is low).
  • You want short-lived access tokens + refresh tokens to keep "log everyone out" cheap.

There, JWTs are fantastic. They're just not the right tool for a public API hit by every install of your shipping product.

If you've made it this far and you're licensing software, you should probably be using KeyStack. Sign up — it's free for hobby projects.