Backend
API key design: entropy math, prefixes, and why sk_live_ is genius
yuus_company Dev.to (EN Zone)
1 views
At some point every backend grows an API key system. Most teams improvise the format — and the format matters more than you'd think. Here's the 10-minute version of what I wish I'd known.
1. Length is entropy — do the math once
The security of a key comes from its random body. With a character set of size C and body length L:
entropy = L × log₂(C) bits
Some real numbers for the usual A-Za-z0-9 set (C = 62, log₂ ≈ 5.95):
Body length
Entropy
Verdict
16 chars
~95 bits
weak-ish for a public key
22 chars
~131 bits
the common baseline (≥128 bits)
32 chars
~190 bits
comfortable margin, still short enough to handle
If you exclude look-alike characters (0/O, 1/l/I) for human readability, the set shrinks — just add 2–3 characters of length and you're back to the same strength.
(A UUID v4, by the way, is 122 bits. It clears the bar, but keeps reading...)
2. The prefix is not decoration
Stripe's sk_live_ / sk_test_ and GitHub's ghp_ prefixes do three jobs:
Environment safety — you can tell at a glance (and assert in code!) that a test key never hits production endpoints.
Incident triage — when a key fragment shows up in a log or error report, the prefix tells you instantly which environment leaked.
Secret scanning — this is the big one. A distinctive prefix is a regex-able pattern. GitHub secret scanning, truffleHog, and friends can detect your keys in public commits and auto-revoke them. A bare random string or UUID is invisible to these tools.
This is why "just use a UUID" is the wrong answer even though the entropy is fine.
3. Storage rules (the part everyone gets wrong)
Hash the key server-side (SHA-256 is fine — keys are high-entropy, unlike passwords, so you don't need bcrypt's slowness). Store the hash, compare hashes on auth.
Show the plaintext exactly once, at issue time. If the user loses it, they rotate.
Keep a short displayable suffix (...x7Kq) so users can identify keys in a dashboard without you storing the secret.
Track created / expires / last-used per key and reap unused ones.
Have a rotation path before you need it: issue new → dual-accept window → revoke old.
4. Prototyping a format
Before committing to a format, it's worth generating a batch and looking at it: does it survive double-click selection? Does it wrap badly in your docs? Is the chunked version (XXXX-XXXX-...) actually more readable for your case?
I put together a small API key generator for exactly this — configurable prefix, body length, chunking, and character rules, generated locally with crypto.getRandomValues (nothing sent to any server). Handy for staging keys and for eyeballing format candidates with your team.
TL;DR
≥128 bits of entropy: 22+ random chars over A-Za-z0-9.
Always use a distinctive prefix — it's what makes secret scanning work.
Store hashes, show plaintext once, track usage, plan rotation.
UUIDs pass the entropy test but fail the operability test.
Read original: https://dev.to/yuus_company/api-key-design-entropy-math-prefixes-and-why-sklive-is-genius-44fp
← Previous
No, you can't decrypt a bcrypt hash — here's what to do instead
Next →
Everything except the server: what it costs to run one WordPress site for a year
Related
P
PKCE Downgrade Attack: When the Authorization Server Accepts Both Flows
Backend
0
DEV Community
O
OAuth Flow CSRF: How a Missing State Parameter Enables Forced Authorization
Backend
0
DEV Community
I
I Built a Version Bump Tool in Rust That Is 10,000x Faster Than Its Python Counterparts.
Backend
0
DEV Community
S
StyleSmuggler: Unpatched Magento Zero-Day Is Backdooring Stores Right Now
Backend
0
DEV Community
Comments0
No comments yet — be the first