Random String Generator

Generate random strings of any length from exactly the character sets you choose, one at a time or a thousand at once. Built for the values developers actually need — API keys, tokens, webhook secrets, test fixtures and identifiers — with cryptographic randomness, an entropy readout, and an optional prefix so a key announces what it is.

Characters are drawn from crypto.getRandomValues with mask-and-reject sampling, so every character in the set is equally likely. Nothing is requested from a server — values generated here have never existed anywhere else. The prefix is not counted towards entropy, because it is not secret.

Press Generate to create strings.
Your generated strings will appear here.

What this tool is for — and what it is not

This is a generator for machine-handled random values. The things it is designed to produce are API keys, bearer tokens, webhook signing secrets, session identifiers, database seed data, unique test fixtures, invite codes, one-time codes and any other string whose only requirement is that nobody can guess it and nothing else already has it.

It is deliberately not a password generator — if that is what you came for, the password generator is the page you want. The distinction changes almost every design decision. A password is created by a person, remembered or stored by a person, and typed by a person, which means the best modern advice is a long passphrase of ordinary words and the right home for it is a password manager. A machine credential has none of those constraints: nobody types a 40-character API key, so length is free and density is a virtue. Optimising one for the other's requirements produces a bad version of both.

One consequence worth stating plainly: if you do use this page to produce a value that will protect something real, treat the result the way you would treat any secret. It is generated locally and never transmitted — you can confirm that in the network tab, because pressing Generate issues no requests at all — but it will sit in your clipboard and possibly your browser history of visited pages. For the highest-value secrets, generating on your own machine with openssl rand -base64 32 or head -c 32 /dev/urandom | base64 is the habit to build. For a test key, a fixture, or a staging webhook secret, this page is exactly the right amount of ceremony.

Entropy: the number that actually matters

"Random enough" is not a property of how a string looks. It is a property of how many strings it could have been, and that is measured in bits of entropy: length × log₂(character-set size). Each bit doubles the search space, so the figure is worth reading carefully.

Character setSizeBits per characterLength for 128 bits
Digits only103.3239
Hex164.0032
Lowercase letters264.7028
Lowercase + digits365.1725
Alphanumeric, mixed case625.9522
Alphanumeric + symbols~946.5520

Useful reference points. 64 bits is not enough for anything an attacker can test offline; specialised hardware chews through that space. 128 bits is the standard "cannot be brute-forced by anyone, ever, with any conceivable hardware" threshold and is the right floor for an API key or a signing secret. 256 bits is what you use when the value protects something that must survive decades, and costs nothing but characters.

The table also shows why arguing about symbols is a poor use of energy. Going from 62 characters to 94 buys 0.6 bits per character. Adding two characters to a 62-symbol string buys 11.9 bits. Length is the cheap lever, and it does not break anything downstream — whereas symbols must be escaped in URLs, quoted in shell commands, wrapped carefully in YAML, and are a common cause of an environment variable arriving truncated. The default settings here are alphanumeric for that reason.

The meter above reports the entropy of the random portion only. A prefix such as sk_test_ contributes nothing, because it is public by design — its job is to make a leaked key identifiable, not to make it unguessable.

Unbiased sampling, and why % is not good enough

Every character here is chosen by mask-and-reject sampling rather than by taking a random byte modulo the alphabet size, and the reason is a genuine correctness issue rather than a stylistic preference.

A random byte has 256 equally likely values. If the character set has 62 members, 256 ÷ 62 is 4 with a remainder of 8 — so eight of the sixty-two characters get an extra byte mapped onto them and appear about 25% more often than the other fifty-four. The strings still look random. You could stare at a thousand of them and never notice. But the distribution is skewed, the true entropy is below the arithmetic, and with an awkward set size the skew becomes severe.

Rejection sampling removes it. Take the smallest bit mask that covers the set size, apply it to a random byte, and if the result lands beyond the end of the set, discard it and draw another byte rather than folding it back. Every value that survives is equally likely because every value came from the same uniform range and no value was ever mapped to twice. Some bytes are wasted; at these volumes the cost is unmeasurable. The same reasoning, with more detail on the failure mode, is set out on the NanoID generator.

The source of the bytes matters just as much as how they are consumed. crypto.getRandomValues is the browser's CSPRNG, seeded from the operating system's entropy pool. Math.random is a fast pseudo-random generator with a small internal state that can be recovered from a handful of outputs, after which every past and future value is predictable. Any tool that generates "secure" strings with Math.random is producing values that look fine and are not safe — and it has happened in widely used libraries more than once.

Designing an API key

If you are issuing keys rather than consuming them, the random part is the easy bit. The decisions around it are what make a key scheme pleasant or painful to live with.

  • Give it a prefix. A key that starts sk_live_ or ghp_ can be recognised on sight, by a log scrubber, and by secret-scanning tools that watch public repositories. This is the single highest-value feature of a key format, and the prefix box above exists for it.
  • Encode the environment. sk_test_ against sk_live_ stops the entire class of incident where a staging job runs against production data.
  • Store a hash, not the key. Keep a SHA-256 digest and a short display prefix so a database leak yields nothing usable. Show the key once at creation and never again — the hash generator will produce the digest, and the reason to use a fast hash here rather than a password hash is that the input already has full entropy.
  • Make rotation routine. Support two live keys per account so a rotation is "create, deploy, revoke" instead of an outage. If rotation is painful, nobody rotates, and a key leaked two years ago is still valid today.
  • Scope it. A key that can only read one resource limits the damage when it leaks. Denying an out-of-scope request with 403 Forbidden and a missing or malformed key with 401 Unauthorized is the distinction the API authentication guide walks through.
  • Keep it out of the URL. Query strings land in server logs, proxy logs, browser history and Referer headers. Send credentials in a header — the bearer token guide covers the syntax, and the HTTP headers reference covers where custom key headers belong.

Once the key exists, the fastest way to confirm the whole path works is to send a request with it. Paste it into the Auth tab of the API tester as a bearer token or a custom API key header and watch what your endpoint returns — including the negative cases, which are the ones nobody tests: a revoked key, a key for the wrong environment, and no key at all.

Other things this is good for

Test fixtures. Hard-coded values in a shared test environment collide the moment two builds run at once, and the resulting failure looks like a flaky test rather than a data problem. Generating a batch of unique strings per run removes the whole category. Use the bulk options above and the JSON array format to paste straight into a fixtures file — the JSON formatter will tidy the result.

Webhook signing secrets. A shared secret used to compute an HMAC over each payload, letting the receiver confirm the request genuinely came from you. Thirty-two or more alphanumeric characters is the right size, and the receiving side should compare signatures with a constant-time function rather than ==.

One-time codes and invite tokens. Short-lived, single-use values where you can afford fewer characters because the window is small and attempts are rate-limited. If a person will type it, turn on the look-alike exclusion and keep it uppercase.

Cache-busting and unique filenames. A random suffix guarantees a distinct object key in a bucket without a round trip to check.

Database seeding. A thousand distinct strings pasted into a script is often quicker than writing the generator, and every batch here is checked for duplicates before it is shown.

Where a value is an identifier rather than a secret, a structured scheme is usually better than a free-form random string. If it needs to sort by creation time, use a ULID. If it needs a standard binary representation and a native database column, use a UUID. If it needs to be short and URL-safe with no structure at all, use a NanoID. Reach for a free-form random string when the format is genuinely yours to choose — which is most often the case for secrets rather than for keys in a database.

Common mistakes

Reusing one secret in every environment

Development, staging and production should never share a signing secret or an API key. When they do, a value pasted into a chat while debugging becomes a production credential, and the audit trail cannot tell you which environment used it. Generate a separate value per environment; it takes seconds.

Committing the value to the repository

A secret in git history stays in git history through every fork, clone and mirror, and removing it means rewriting history everywhere. If it has already happened, rotate the secret rather than trying to erase it — the rotation is the fix, the history rewrite is cosmetic.

Deriving a secret from something guessable

A "random" string built from a company name, an environment name, a date or a counter is not random at all. Neither is one produced by a shell script that seeds from $RANDOM or from the current time — a value generated at a predictable moment has far less entropy than its length suggests.

Assuming length equals strength

A 64-character string drawn from a 4-character alphabet has 128 bits; a 64-character string that is actually a repeated pattern has almost none. Read the entropy figure, not the length.

Logging the value

Secrets end up in logs by accident constantly: a debug print of a request object, an error report including headers, a crash dump. Redact credentials at the logging boundary rather than trusting every call site to remember. This site's own request history applies exactly that treatment to URLs before anything is stored — see the privacy page for what that means in practice.

Frequently asked questions

Are these strings really random?

They come from crypto.getRandomValues, the browser's CSPRNG, not from Math.random — whose internal state can be recovered from a few outputs, making every later value predictable.

Are the strings generated on your server?

No. Everything happens in your browser and nothing is transmitted. Open the network tab and press Generate: there are no requests at all.

How long should an API key be?

At least 128 bits of entropy — 22 alphanumeric characters or 32 hex characters. Thirty-two alphanumeric characters is about 190 bits and a comfortable default, since nobody has to type it.

Is this a password generator?

No. This is for machine-handled values: keys, tokens, fixtures and identifiers. A password is typed and remembered by a person, which favours a long passphrase, and belongs in a password manager. Use the password generator for that job.

What does the entropy figure mean?

How many equally likely values the string could have been, on a log scale: n bits means 2n possibilities. 64 bits is weak against offline attack, 128 bits is comfortable, 256 bits is beyond any foreseeable hardware.

Why exclude ambiguous characters?

Because 0/O, 1/l/I and sometimes 5/S are indistinguishable in many fonts. If a human will ever read, print, dictate or retype the value, removing them eliminates a whole class of error for a small entropy cost you can recover with one extra character.

Should I include symbols in an API key?

Usually not. Symbols need escaping in URLs, shells, YAML and environment variables, and each layer is a chance to corrupt the value. Two more alphanumeric characters buy more entropy than switching to a symbol set does.

How should generated secrets be stored?

In a secret manager or platform environment configuration, never in the repository. For keys you issue to others, store only a hash plus a short display prefix, and show the full value once.

Can I generate strings in bulk?

Yes, up to a thousand at a time, and every batch is checked so all values in it are distinct — useful for seeding a database or filling a fixtures file.

Related tools and reference