A JWT for testing is a compact, HS256-signed token built from a strict JSON claims object and a non-production secret of at least 32 UTF-8 bytes, encoded as three base64url segments separated by dots. Browser-based tools generate these tokens locally using the Web Crypto API, so claims and secret material stay in the current tab and never leave the machine. The protected header is fixed to {"alg":"HS256","typ":"JWT"}, which prevents the common testing failure mode of accidentally producing an unsigned, mismatched, or algorithm-confused token. Because HS256 is a message authentication code rather than encryption, anyone who receives the token can decode the header and payload without the secret — a useful property during testing, since it lets you inspect exactly what your verifier will see. The signature segment only proves the token was not modified after generation when a verifier uses the matching secret. Used carefully, a local test JWT replaces the boilerplate code many developers paste into scripts just to exercise an auth middleware.

Why Developers Generate JWTs Locally for Testing
Testing authenticated HTTP endpoints, websocket handshakes, or middleware chains usually requires a syntactically valid token with the right shape — long before any identity provider is wired up. A few common situations where a local generator is faster than spinning up an auth server:
- Mocking bearer-token auth on a development API while the real OIDC provider is still being provisioned.
- Reproducing a production-shaped token to mirror a bug report without revealing real credentials.
- Feeding a verifier library the expected segment lengths and claim names to confirm it parses correctly.
- Stress-testing rate limiters, role-based access controls, and audit log shapes.
- Running demos, workshops, and onboarding exercises where attendees need working tokens without signing up.
In each case the priority is shape and signature correctness, not secrecy. The token only has to look like a real one well enough for your code path to accept it.
How an HS256 Test Token Is Structured
A compact JWT is three base64url strings joined by dots: header.payload.signature. None of the segments are padded with "=" characters; the URL-safe alphabet replaces "+" with "-" and "/" with "_". The generator locks the protected header to {"alg":"HS256","typ":"JWT"} so the first segment never varies from a test run to the next, which is exactly what your verifier expects.
| Segment | Content | Purpose |
|---|---|---|
| Header | {"alg":"HS256","typ":"JWT"} | Tells the verifier the signature algorithm |
| Payload | Your strict JSON claims object | Carries subject, audience, expiration, and any custom fields |
| Signature | HMAC-SHA-256(header + "." + payload, secret) | Detects modification under the matching secret |
The payload is the only segment you fully control. The generator accepts a strict JSON object: no arrays at the top level, no comments, no trailing commas, no undefined, no NaN, no Infinity, and no JavaScript expressions. Anything else is rejected before the signature is even computed, because loose JSON would silently produce a different bytes-on-the-wire payload than the one you intended to sign.
If you want to peek at what your verifier will see, paste the copied token into a browser-based JWT decoder — it shows header and payload as decoded objects without exposing the secret.
Generate a Test JWT Step by Step
The workflow below assumes you only need a token for local testing, demos, or library validation — not for a live system.
- Open the JWT Generator in your browser. The page runs entirely client-side, so no claims or secrets are transmitted.
- Paste a strict JSON claims object into the claims field. For example: {"sub":"user-123","iss":"https://test.local","aud":"api-test","exp":1893456000}.
- Enter a non-production secret of at least 32 UTF-8 bytes. If you don't have one handy, click the random button — it generates 32 cryptographically random bytes and displays them as 64 hexadecimal characters, which are then used as the raw UTF-8 HMAC secret. Character count and byte count can differ for non-ASCII secrets, so plan accordingly.
- Generate the HS256 token. Review the three segments, confirm the header reads {"alg":"HS256","typ":"JWT"}, confirm the payload matches what you pasted, and check that the secret never appears anywhere in the output.
- Copy the token and verify it with the destination JOSE library using explicit algorithm, issuer, audience, lifetime, and key policy. A generated token that passes verification is the strongest signal that the wire format is correct.
Verify the Test Token With Your JOSE Library
Generating a token is half the job; the other half is confirming that the verifier you plan to ship accepts it. Verification has to be explicit, because implicit defaults are how algorithm-confusion bugs slip into production code.
- Pin the algorithm. The library should refuse anything other than HS256, since the generator never produces RS256, ES256, EdDSA, JWE, or unsigned tokens.
- Pin issuer (iss) and audience (aud). NumericDate values like exp and nbf are seconds since the Unix epoch, not JavaScript milliseconds — a 1,000× error that frequently hides in test fixtures.
- Apply clock skew tolerance deliberately. Most libraries default to zero; if you set leeway, set it to a small constant and document it.
- Test a tampered token. Flip a character in the payload segment, re-verify, and confirm the signature check fails. If it doesn't, your verifier is misconfigured.
- Test a wrong secret. Sign with one secret and verify with another, then confirm the result is rejection. This catches the "test library accepted anything" misconfiguration early.
This is also where a maintained JOSE library — backed by the JWS specification described in RFC 7515 — earns its place. Verification, algorithm allowlists, key discovery, rotation, and error handling belong in production code, not in a generator page.
What the JWT Generator Will and Won't Do
The contract is deliberately narrow so that test behavior is predictable:
- It signs HS256 only and rejects other algorithms at the header level.
- It validates strict JSON object claims and rejects everything else before signing.
- It encodes segments as UTF-8 and converts them to unpadded RFC 4648 base64url.
- It signs the exact byte sequence header + "." + payload with browser-native HMAC-SHA-256.
- It does not auto-add iat, exp, nbf, iss, sub, aud, jti, or any other claim. You are responsible for those values.
- It does not encrypt, does not produce JWE, and does not generate RSA or EC key pairs.
- It does not contact an identity provider, publish a JWK, store a key, or pick a kid.
- It does not self-verify the token it just created; you verify against your own library.
Testing Safety Rules You Should Not Skip
A test token is still a bearer credential, and the testing mindset often blurs into habits that don't survive contact with production. Keep these rules on the wall above your keyboard:
- Use only non-production claims and secrets on the generator page. Treat the random button output as visible development material, not an automatically provisioned production secret.
- Never put passwords, private keys, or personal records into a JWT just because it is signed. Signing is not encryption; anyone who receives the token can decode its header and claims without the secret.
- Rotate or revoke any real secret or active token that ends up pasted into the wrong place. Local processing does not make disclosure harmless.
- Watch where the token lands. Clipboard history, screenshots, browser extensions, terminal logs, support tickets, and chat threads all leak bearer credentials in subtle ways.
- Match the secret to the HS256 floor. The 32-byte minimum exists because the underlying hash output is 256 bits; weaker test secrets produce weaker signatures and misleading confidence in your verifier.
Done carefully, a browser-generated HS256 token is one of the fastest ways to confirm that your auth code parses, validates, and rejects correctly before the real identity provider is in the loop, and it costs nothing more than a careful JSON object and a long enough secret.