Ideapreneur Nepal logoSuperPreneur for Developers v1.0

Generating the nonce

The nonce is a one-time random string that your server creates for every page load. It is what stops a token from being used by anyone except the page that asked for it. A good one looks like this: 8nZk2Z-Msfpa9GWFqIiP__s6vgeizMt0.

Rule Detail
Who creates it Your server, inside POST /api/nonce. Never the browser and never SuperPreneur
Randomness From a cryptographically secure source. 24 random bytes is the recommended size
Format URL-safe Base64 without padding: letters, digits, - and _. Length 16 to 128; 24 bytes gives 32 characters. Pattern ^[A-Za-z0-9_-]{16,128}$. SuperPreneur refuses anything else
Lifetime 2 minutes
Use Once. Remove it the moment /api/session receives it, before you call the identity provider
Where it lives On your server, looked up by the nonce itself. Never in a cookie or the URL
Never Build it from a user id, the time or a counter; reuse it across page loads; use Math.random(), rand() or a version 1 UUID

Creating it#

# Python 3
import secrets
nonce = secrets.token_urlsafe(24)              # 32 characters
// Node.js 16 or newer
const nonce = require('node:crypto').randomBytes(24).toString('base64url');
// Go
b := make([]byte, 24)
if _, err := rand.Read(b); err != nil { /* handle it */ }   // crypto/rand
nonce := base64.RawURLEncoding.EncodeToString(b)            // encoding/base64
// Java 8 or newer
byte[] b = new byte[24];
new SecureRandom().nextBytes(b);
String nonce = Base64.getUrlEncoder().withoutPadding().encodeToString(b);
// PHP 7 or newer
$nonce = rtrim(strtr(base64_encode(random_bytes(24)), '+/', '-_'), '=');

The Python, Node, Go and Java versions were run and each produced a valid 32-character nonce. The PHP line was not run; it is the standard recipe for URL-safe Base64.

Storing it and using it up#

On one server a dictionary in memory is enough: store nonce -> expiry time, delete expired entries when you add new ones, and delete the nonce as soon as it is used. The complete examples do exactly this.

If you run several server instances, they must share the nonces (and your sessions), or a request can land on an instance that has never seen the nonce. With Redis:

SET nonce:<nonce> 1 EX 120      # when you create it: expires in 120 seconds
GETDEL nonce:<nonce>            # when /api/session arrives: returns 1 once, then nothing

GETDEL reads and deletes in one step, so two requests with the same nonce can never both succeed. It needs Redis 6.2 or newer; on older versions use DEL and check that it returned 1.

Why it matters#

Without a nonce, anyone who got hold of a token (from a screenshot, a log, a shared link) could present it to your server within its 60 seconds. With one, the token only works for the page load whose nonce your server issued, and only once. Two checks protect you: your server refuses a nonce it did not issue or has already used, and the identity provider refuses a token whose nonce differs from the one you send.