Generating a UUID for a Session Token or CSRF Nonce

Generate a cryptographically random UUID for a session ID or CSRF nonce, and see why Math.random() is the wrong source for either one.

ZERO UPLOAD · ALL LOCAL
  1. UUID v1, v4, and v7 are generated automatically on load. Click Regenerate All to get a fresh set at any time.
  2. Use the format toggle to switch between Standard, UPPERCASE, No Hyphens, Braces, and URN display formats. The format applies to all three versions at once.
  3. Click Copy next to any UUID to copy it to the clipboard in the currently selected display format.

What to look for

  • v4 (fully random)
  • 122 bits (CSPRNG)
  • ~1 in 10 trillion per 1 trillion tokens

v4 is the version to use for a session token or CSRF nonce; v7's timestamp bits would reveal issue time and reduce the unpredictable portion.

FORMAT
V1 Time-based
V4 Random
V7 Time-ordered

Generating a UUID for a Session Token or CSRF Nonce

A session token or CSRF nonce only works as a security control if an attacker cannot guess or predict it. That requirement rules out more identifier-generation methods than you might expect, including the one built into JavaScript that looks like it should work: Math.random(). This tool generates every UUID with your browser's cryptographically secure random number generator instead, the same entropy source that protects TLS key exchange, so the identifier is safe to use anywhere unpredictability is the actual security property you need.

Why Math.random() is the wrong tool for a token

JavaScript's Math.random() is a pseudo-random number generator built for speed and statistical distribution, not for unpredictability against an attacker.1 V8, the engine behind Chrome and Node.js, generates it with an algorithm called xorshift128+, and Firefox and Safari adopted the same algorithm; the V8 team is explicit that despite being a real improvement over its predecessor, it remains unsuitable for hashing, signatures, or encryption.2 That is an acceptable trade-off for shuffling an array or picking a random UI color; it is a disqualifying one for anything that stands between an attacker and an authenticated session.

A session token generated from Math.random() output is not cryptographically unpredictable, which means an attacker with enough observed samples could, in principle, forecast a future token value and hijack a session without ever seeing the victim's actual cookie. A CSRF nonce built the same way loses the one property that makes it useful: an attacker who can predict the nonce can forge a valid request without needing to read the victim's page at all.

What a CSPRNG changes about that guarantee

A cryptographically secure pseudo-random number generator, CSPRNG, is built specifically so that observing past outputs gives an attacker no advantage in predicting future ones. Browsers expose one through the Crypto interface, most directly via crypto.getRandomValues() and, for UUIDs specifically, crypto.randomUUID(); rather than generating entropy in JavaScript itself, the method fills its output using a platform-specific random number source such as the operating system's own generator.3 That is the source this tool draws from for every UUID it generates, v4 included, which is exactly the version to reach for when the value needs to double as a token.

The distinction matters because the two APIs live right next to each other in most editors' autocomplete, and picking the wrong one compiles and runs without any warning. Nothing about the resulting string looks different: a token built from Math.random() and one built from crypto.randomUUID() are both 36-character hex strings, and only the generation method behind them determines whether an attacker can eventually predict the next one.

How crypto.randomUUID() sources its randomness

Calling crypto.randomUUID() does not generate randomness inside the JavaScript engine at all; it delegates to the operating system's own random number generator, the same pool that services TLS handshakes, key generation, and other security-sensitive operations at the OS level. That shared entropy source is audited and maintained far more rigorously than any userland PRNG a web page could implement itself.

For a UUID v4 used as a session token, 122 of its 128 bits come directly from that CSPRNG, with only the version and variant nibbles fixed by the format. That leaves the same order of entropy backing a 128-bit key would offer, comfortably more than enough to make guessing a valid, active token infeasible for any realistic attacker within a session's lifetime.

Where the token still needs the rest of your system to cooperate

Generating an unpredictable value only secures one link in the chain. The token still needs to travel over HTTPS so it cannot be captured in transit, get marked HttpOnly and Secure if it lives in a cookie so client-side scripts and unencrypted connections cannot read it, and expire on a reasonable timeline so a leaked token has a limited window of usefulness.4 A cryptographically random UUID is necessary for a safe token; it is not sufficient on its own.

Generating and using the token

Click Regenerate All and copy the V4 value directly; it is already formatted for use as a session identifier or CSRF nonce with no further processing required. Every value on this page, v1, v4, and v7 alike, is produced with the same browser CSPRNG, so the copy-ready string never touches Math.random() at any point in its generation.

The Standard display format, lowercase with hyphens, is the most portable choice for a token that will get set as a cookie value or an HTTP header, since it matches what most session-handling libraries expect to parse without modification. Switching to a different display format changes only the surrounding punctuation; the underlying 128-bit value, and the security guarantee behind it, stays identical either way.

Confirming the entropy source yourself

If you want to verify the claim rather than take it on faith, open your browser's console on any page and compare the two functions directly: crypto.randomUUID() and Math.random() are both available globally, and inspecting the properties of the Crypto interface confirms it delegates to the platform's own random source rather than a JavaScript-level implementation. That same crypto.randomUUID() call is what runs every time you click Regenerate All here.

When to use this

Use this guide whenever you need a session identifier, CSRF nonce, or API key that has to be unpredictable to an attacker, not just unique.

Examples

Choosing a source of randomness for a new session token

Before
Before: your code currently generates session IDs with Math.random().toString(36), a common but insecure shortcut.
After
Generating a V4 UUID here instead gives you a 128-bit value sourced from crypto.randomUUID(), with 122 bits of CSPRNG-backed entropy behind it, ready to set directly as the session cookie's value.

Verifying no network request fires during generation

Before
Before: open your browser's DevTools Network tab, then click Regenerate All.
After
No request appears in the Network tab, confirming the UUID, and the entropy behind it, never left your browser or touched a server CapyToolkit controls.
Sources
  1. 1.

    OWASP Foundation, "Insecure Randomness," owasp.org, accessed August 2026. https://owasp.org/www-community/vulnerabilities/Insecure_Randomness

  2. 2.

    V8 Team, "There's Math.random(), and then there's Math.random()," v8.dev, accessed August 2026. https://v8.dev/blog/math-random

  3. 3.

    Mozilla Developer Network, "Crypto: getRandomValues() method," developer.mozilla.org, accessed August 2026. https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues

  4. 4.

    OWASP Foundation, "Session Management Cheat Sheet," cheatsheetseries.owasp.org, accessed August 2026. https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html

FAQ