API key generator
Secure random API keys with a prefix and a checksum, made in your browser. Pick a format, copy, done.
About 190 bits of randomness, plus a prefix and a CRC32 checksum
2 to 10 lowercase letters or digits
Your keys appear here.
Generated in your browser with crypto.getRandomValues. Nothing is sent anywhere.
Want your customers to create keys like these themselves? Try UsageRail free.
The check runs in your browser too.
What makes a good API key
An API key only has one job: prove that a request comes from a customer you issued it to. That puts three requirements on the format, and two nice-to-haves.
- Unguessable. The random part has to come from a cryptographically secure random generator and carry at least 128 bits of entropy. The hex and base64url options carry 256 bits, and the 32-character base62 secret in the prefixed format about 190 (32 × log2 62). A UUID v4 has 122 random bits, a little under that bar, which is why UUIDs make better IDs than secrets.
- Shown once. You show the full key when it's created and store only a hash. If someone reads your database, they get hashes, not working keys.
- Revocable. Each key needs its own record, so you can revoke one key without touching a customer's other keys.
- Recognizable (nice to have). A prefix tells your customer, your support team and secret scanners whose key it is and which environment it belongs to.
- Self-checking (nice to have). A checksum lets your server reject a mistyped or made-up key without a database lookup.
API key format, explained
The prefixed format this generator uses looks like this:
acme_live_k7Gx2PqAHn3Lq8WvZr2Tb6Yd1Kx9Pe4Ms7Jc0Uf50Ysd8S| Part | In the example | What it's for |
|---|---|---|
| Prefix | acme | Your product. 2 to 10 lowercase letters or digits. Makes leaked keys easy to attribute and easy to scan for. |
| Environment | live | live or test, so nobody ships a test key to production without noticing. |
| Key ID | k7Gx2PqA | 8 characters. Stored in plain text and used to find the key's record, so the server never has to compare against every hash. |
| Secret | Hn3Lq8Wv…Jc0Uf5 | 32 random base62 characters, about 190 bits. This is the part that must stay secret. |
| Checksum | 0Ysd8S | 6 characters: the CRC32 of everything before it, encoded in base62 and padded with zeros. |
The underscores matter too. They aren't base62 characters, so the parts never run together, and because underscores count as part of a word, double-clicking the key usually selects all of it.
The checksum is not a security feature: anyone can compute a CRC32. It stops honest mistakes and random noise. A key with one wrong character fails the check, so your server can answer 401 straight away instead of hitting the database, and a secret scanner can ignore strings that only look like keys. Try it in the checker above: paste a generated key, change one character, and the checksum no longer matches.
API key examples from well-known APIs
The same ideas show up in the keys you already use.
- GitHub moved to prefixed tokens in April 2021:
ghp_for personal access tokens,gho_for OAuth tokens,ghs_for server-to-server tokens, and a few more. The last 6 characters are a CRC32 checksum encoded in base62, padded with leading zeros. GitHub said the prefixes alone would bring secret scanning's false positive rate down to 0.5%, and that the checksum lets it reject fake tokens offline. - Stripe puts the key type and the mode in the prefix:
sk_live_andsk_test_for secret keys,rk_live_for restricted keys,pk_live_for publishable keys that are safe to put in front-end code. If you create a live secret key yourself, Stripe shows it once and can't reveal it again.
Both prefixes tell you at a glance who issued a token and what kind it is, and Stripe's also say whether it's live or test. A product prefix plus an environment label gives your own API keys the same property.
How to store and check API keys
- Generate the key on your server when the customer asks for one, using a secure random source.
- Show the full key once, with a copy button and a clear note that it won't be shown again.
- Store the key ID, a SHA-256 hash of the full key, the customer it belongs to, its status and an optional expiry date. Don't store the key itself, and keep it out of logs and error reports.
- On each request: check the format and checksum first, look up the record by key ID, compare hashes in constant time, then check status and expiry.
- To rotate, issue a new key and give the old one an expiry date a day or two out, so the customer can switch without downtime.
A fast hash like SHA-256 is fine here. Slow password hashes such as bcrypt exist because people choose guessable passwords. A key with 190 random bits can't be brute-forced however fast the hash is.
If you'd rather not build this part, UsageRail gives your customers a portal where they create, rotate and revoke keys in this format, and its SDK checks them inside your API process. The rate limiting guide covers what to do once a request has a valid key.
Generate an API key in code
Node.js, 32 random bytes as base64url:
import { randomBytes } from "node:crypto";
const apiKey = randomBytes(32).toString("base64url");Python, the same thing with the standard library:
import secrets
api_key = secrets.token_urlsafe(32)Both give you 256 bits of randomness. Add your own prefix in front (for example acme_live_) if you want keys people can recognize.
Is it safe to generate API keys in a browser?
Yes, as long as the page uses the browser's cryptographic random generator. This one calls crypto.getRandomValues (and crypto.randomUUID for UUIDs), which browsers back with the operating system's secure random source. The keys are created on your device and never sent to us; you can disconnect from the internet and the generator keeps working.
For keys your customers will use in production, though, generate them on your server at the moment a customer asks for one. That way the key exists in exactly one place before you hash it, and you never have to paste it anywhere.