What is a nonce and why it matters
A nonce (number used once) is a unique value used only once to prevent replay attacks. If an attacker captures a valid request and resends it, the already-used nonce is rejected.
Nonces are critical in: OAuth flows (prevents CSRF), JWT tokens ('jti' claim for one-time use), webhooks (validates payload wasn't manipulated), CSP headers (allows safe inline scripts), and financial transactions (prevents double-spend).
An effective nonce must be: unpredictable (cryptographically random), unique (non-repeatable), time-limited (expires after X seconds or first use). Using timestamps alone is NOT enough: they're predictable. Combine timestamp + randomBytes + HMAC for robust nonces.
Implementing nonces in Node.js and browsers
In Node.js, use crypto.randomBytes(16) from the native module. For URL-safe strings, convert to base64url or hex. Example: crypto.randomBytes(16).toString('base64url') generates strings like 'a3f8B2kL9xR4'.
In modern browsers, use crypto.getRandomValues(new Uint8Array(16)) and convert to hex with Array.from(bytes).map(b => b.toString(16).padStart(2,'0')).join(''). Avoid Math.random(): it's not cryptographically secure.
For timestamped nonces, concatenate millis + random: Date.now() + '_' + crypto.randomBytes(8).toString('hex'). This allows temporal ordering while maintaining uniqueness. Store used nonces in Redis with 5-10 minute TTL to prevent reuse within replay window.
Nonces in OAuth and PKCE
In OAuth 2.0, the 'state' parameter functions as a nonce to prevent CSRF. Generate a random value, store it in session or httpOnly cookie, and validate the callback returns it identically.
PKCE (Proof Key for Code Exchange) uses two nonces: code_verifier (43-128 chars URL-safe random) and code_challenge (SHA256 of verifier in base64url). The authorization endpoint receives the challenge, the token endpoint validates the verifier. This prevents authorization code interception in public apps.
In OpenID Connect, the 'nonce' claim is included in the ID token. The client generates a random nonce, passes it in the request, and verifies the returned token contains it. This binds the token to the specific request, preventing token substitution attacks.
Content Security Policy and script nonces
CSP nonces allow executing safe inline scripts without 'unsafe-inline'. Generate a nonce per request: const nonce = crypto.randomBytes(16).toString('base64'). Add the header: Content-Security-Policy: script-src 'nonce-${nonce}'.
In HTML, each inline script must include the attribute: <script nonce='${nonce}'>...</script>. The browser only executes scripts with correct nonce. Important: the nonce must be different per response (don't reuse between requests).
For SSR frameworks (Next.js, Nuxt), configure the nonce in middleware and pass it to render context. In Express: res.locals.nonce = generateNonce(), then in templates: <script nonce='<%= nonce %>'>. Combine with strict-dynamic to allow scripts loaded by scripts with valid nonce.