Hash crypto & JWT
JWT Secret Keys: Random Bytes, Encoding, and Rotation
Generate random HS256 key material, distinguish encoded text from raw bytes, manage rotation, and test key use without sharing production secrets.
Identify whether the algorithm uses a shared secret
HS256 uses a shared HMAC secret: a party that can verify with that secret can also create matching signatures. Asymmetric signing algorithms use a private signing key and a corresponding public verification key instead. Do not distribute an HS256 secret as if it were a harmless public verification key.
The JWA specification's HMAC section requires key sizes at least as large as the hash output, which means at least 256 bits for HS256. Use cryptographically generated random material. A long predictable sentence or repeated character is not equivalent to a randomly generated key of the same visible length.
Generate bytes and choose a storage representation
const {randomBytes} = require("node:crypto");
const keyBytes = randomBytes(32);
const stored = keyBytes.toString("base64url");
const restored = Buffer.from(stored, "base64url");
console.assert(keyBytes.length === 32);
console.assert(restored.equals(keyBytes));
console.assert(stored.length === 43);
This Node.js example creates 32 random bytes and round-trips them through unpadded Base64URL text. It intentionally does not print the key. The Node crypto documentation describes randomBytes. Store generated production material through the deployment's intended secret-management path rather than committing the sample's output into source control.
The 43-character encoded value represents those same 32 bytes. Encoding changes the representation, not the amount of randomness. A hex representation would use 64 characters for the same bytes. Adding a readable prefix can help identify a secret's purpose, but the prefix contributes no unpredictable entropy.
Agree on the exact bytes used by both sides
If the signer decodes the stored Base64URL value into raw bytes but the verifier treats the visible text as UTF-8, they use different keys. Both configurations may look plausible, yet the signature will fail. Document whether the configured secret is raw text, encoded bytes or a structured key object.
The local JWT Secret Key Generator offers several output formats. Its byte-based formats and alphanumeric length setting do not measure the same thing. Choose the format required by the consuming library and verify the round trip rather than estimating strength from the number of visible characters.
The browser's HS256 signing and checking tools interpret their secret field as text. If you copy an encoded random value into that field, those text bytes become the HMAC key there. A separate backend configured to decode the same text must not be assumed to produce the same signature.
Limit where the key can be read or used
Keep production signing material out of browser bundles, public repositories, example configuration files and ordinary support logs. Review who and what can read it in the deployment environment. A setting named SECRET is not protected merely by its name, and Base64 encoding does not encrypt it.
Use separate keys where the system's trust boundaries require separation, such as independent production and test environments. This makes accidental acceptance of a test token less likely and reduces the consequences of a test-system exposure. Coordinate that separation with the issuer and audience checks in each verifier.
Plan replacement before the key is compromised
Define how a new signing key is introduced, how verifiers learn the permitted key set and when the previous key stops being accepted. A key identifier can select an approved key, but must not cause arbitrary file reads or unchecked remote retrieval. Follow the issuer's supported rotation mechanism.
Account for the maximum lifetime of already issued tokens and any explicit revocation requirement. Removing an old key immediately invalidates tokens signed with it; leaving it accepted forever defeats the intended retirement. A suspected compromise can require a faster response than a routine scheduled rotation.
Test key handling without retaining secret output
Use ephemeral fixture keys to test signing with one key, verifying with the matching key and rejecting a different key. Add a raw-bytes versus encoded-text mismatch case. Record pass or fail and the configuration format, not the generated key itself.
Also test the deployed configuration loader: missing values, accidental surrounding whitespace and an unexpected encoding should fail visibly under the application's policy. Do not silently fall back to a tutorial secret, because that can turn a deployment mistake into a shared production credential.


