Random Token & API Key Generator
Cryptographically secure β generated by your browser's CSPRNG, never sent anywhere.
Every API, every auth system, every webhook endpoint eventually needs the same thing: a secret string that no attacker can guess. Yet developers regularly reach for Math.random(), truncated UUIDs, or timestamp-based strings β none of which are cryptographically secure. This guide covers what makes a token truly secure, how browsers generate them natively, and how to pick the right format for different deployment contexts.
Why Math.random() Is the Wrong Tool for Secrets
JavaScript's Math.random() uses a deterministic pseudo-random number generator (PRNG). Given the seed, an attacker can reproduce every value it will ever produce. In practice, the seed is often derived from process state or timestamp data that leaks through browser fingerprinting, timing side-channels, or server logs. Security researchers have demonstrated PRNG seed recovery in V8 β the same engine that runs Node.js and Chrome β with as few as a handful of observed outputs.
The correct alternative is window.crypto.getRandomValues() in the browser or crypto.randomBytes() in Node.js. Both draw from the operating system's entropy pool β hardware events, interrupt timing, thermal noise readings β collected and mixed by the kernel. This is the same source used by openssl rand and /dev/urandom. It is not reproducible from observed outputs.
Entropy: The Actual Security Metric
Token "length" is a proxy measure. What matters is entropy β the number of possible tokens an attacker would need to search through. Entropy in bits is calculated as:
entropy = log2(charset_size) Γ token_length
A 32-character hex token uses a charset of 16 symbols, giving log2(16) = 4 bits per character, so 128 bits of entropy total. That is the widely accepted floor for tokens that need to resist brute-force search even with a massive GPU cluster. A 32-character alphanumeric token (62-symbol charset) delivers log2(62) Γ 32 β 190 bits β meaningfully stronger.
The practical implication: do not judge security by how "random-looking" a token appears. A 16-character hex string that came from crypto is safer than a 64-character string from Math.random().
Choosing the Right Encoding for Your Use Case
Hex (0-9, a-f) produces the most widely compatible format. Every HTTP framework, every database, every terminal handles hex without escaping. The downside is density β only 4 bits per character, so a 128-bit token needs 32 characters. Hex tokens are the right choice for API keys stored in environment variables, database primary keys for secrets tables, and any context where you are unsure about downstream character handling.
Base64url (A-Z, a-z, 0-9, -, _) delivers about 6 bits per character. That means 128 bits of entropy fits in just 22 characters, and 256 bits in 43. The "url" variant replaces + and / from standard Base64 with - and _, making it safe to embed in URLs, JWT headers, query strings, and cookie values without percent-encoding. This is the format used by JSON Web Tokens, OAuth PKCE code verifiers, and most modern session ID schemes. If you are generating bearer tokens or session cookies, Base64url is the best default.
Alphanumeric (A-Z, a-z, 0-9) splits the difference β denser than hex, simpler than Base64url, no special characters whatsoever. Approximately 5.95 bits per character. This format is ideal when tokens will be typed by humans (license keys, one-time codes) or when the downstream system has regex validation that rejects non-alphanumerics. The optional "no ambiguous characters" filter (removes 0, O, l, 1, I) removes visually confusable characters for scenarios where tokens might appear in printed documentation or support tickets.
Modulo Bias: The Silent Flaw in Naive Token Generators
A common implementation mistake is taking a random byte and computing byte % charset.length directly. If the charset size does not evenly divide 256, some characters appear slightly more often than others. For a 62-character alphanumeric charset, the bias is small but measurable β characters at positions 0β5 appear with probability 5/256 instead of 4/256. Over millions of tokens, this statistical skew can be detected and exploited.
The correct fix is rejection sampling: discard any byte value that falls in the remainder region above the largest multiple of charset.length that fits in a byte. The tool on this page uses exactly this approach β it requests a batch of random bytes, skips any that would introduce bias, and continues until the required length is filled. The overhead is negligible: for typical charset sizes, fewer than 2% of bytes are rejected on average.
Prefixes: Making Tokens Self-Describing
GitHub, Stripe, and Anthropic all use a practice worth copying: prefix tokens with a short, fixed string that identifies the token type. ghp_ for GitHub personal access tokens, sk_live_ for Stripe secret keys, sk-ant- for Anthropic API keys. This prefix adds zero security value β it is not secret β but it adds enormous operational value:
- Secret scanning tools (GitHub, GitGuardian, truffleHog) can detect leaks by scanning for the prefix pattern in source code, CI logs, and commit history.
- Developers can identify a token's purpose and environment (live vs. test) at a glance.
- Support teams can confirm a customer is using the right key type without seeing the actual secret.
The entropy of the token is unchanged because the prefix is not secret β only the random suffix matters. A 64-character alphanumeric suffix prefixed with sk_prod_ is still a 64-character secret.
Storage and Transmission Best Practices
Generating a secure token is only the first step. Storage matters just as much. API keys stored in plain text in a database are a single SQL injection away from full compromise. Best practice is to store only a hashed form β SHA-256 of the token β and compare hashes at validation time. The original token is shown to the user once and never stored again. Stripe and GitHub both follow this model.
In transit, tokens belong in HTTP headers (Authorization: Bearer <token>), not in URL query strings. URLs appear in browser history, server access logs, nginx logs, CDN logs, and Referer headers β all places where a plaintext token in the query string will silently leak. A token in the Authorization header is not logged by default in any standard HTTP server configuration.
Environment variables are the accepted standard for application-level storage of API keys and secrets β not config files, not hardcoded strings, not comments in code. Tools like Doppler, HashiCorp Vault, and AWS Secrets Manager formalize this by managing environment injection at deploy time without ever writing secrets to disk in plaintext.
Key Rotation and Expiry
Long-lived API keys are a liability. Any key that was ever transmitted, stored, or even briefly visible is a key that could have been compromised without your knowledge. A rotating key strategy limits the blast radius: keys expire after 90 days (or shorter for high-sensitivity contexts), forcing regular regeneration. Combined with a prefix that encodes the generation date (tok_20261231_), you can identify stale keys in seconds.
For session tokens, OWASP recommends expiry after 15β30 minutes of inactivity for sensitive applications, with absolute expiry after 8β24 hours regardless of activity. Browser CSPRNG-generated session IDs of at least 128 bits entropy meet these requirements trivially β the bottleneck is always policy, not generation quality.