Skip to main content

JWT Token Generator

Sign a JWT (HS256, HS384, HS512) from a JSON payload and shared secret. Runs entirely in your browser using the Web Crypto API.

Reviewed by · Last reviewed

How to use the JWT Token Generator

  1. Edit the payload. Replace the default JSON with your claims. Common standard ones are sub (subject), iat (issued at, Unix seconds), exp (expiry, Unix seconds), aud (audience), iss (issuer), jti (JWT ID), plus any application-specific custom claims.
  2. Type or paste the HMAC secret. This is the same key the verifier will use to validate the token. RFC 7518 recommends a key at least the size of the hash output (32 bytes for HS256, 48 for HS384, 64 for HS512).
  3. Pick the algorithm - HS256 (the OAuth/OIDC default), HS384, or HS512. Match what the verifier expects in its alg allowlist.
  4. Press Add iat + exp to insert the standard time claims at the click of one button. Default sets exp one hour after iat.
  5. Press Generate and the signed JWT appears below. Press Copy to put it on the clipboard, ready to paste into a curl -H "Authorization: Bearer ..." flag, a Postman tab, or a fetch test.

What the generator does under the hood

The tool builds the canonical three-part JWT structure defined by RFC 7519 (JWT) and RFC 7515 (JWS Compact Serialization): base64url(header).base64url(payload).base64url(HMAC(signingInput, key)). The header is always {"alg": "<algorithm>", "typ": "JWT"}, then JSON-stringified and base64url-encoded with no padding. The payload is whatever JSON you typed, also base64url-encoded. The signing input is the first two segments joined with a dot. The signature is computed with crypto.subtle.sign("HMAC", key, signingInput) using the Web Crypto API, then base64url-encoded the same way.

Web Crypto's subtle.sign backs HMAC with the browser's CSPRNG-quality implementation: BoringSSL on Chromium, NSS on Firefox, CommonCrypto on Safari. The HMAC key is imported via subtle.importKey("raw", textEncoder.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]), with extractable: false so even the page itself cannot read the key bytes after import. The whole pipeline is one async function with no fetch calls; you can verify by opening DevTools, switching to the Network tab, and pressing Generate.

When this tool earns its keep

  • Building a test token for a local API that expects a Bearer JWT, when you do not want to stand up a Node script just to mint one.
  • Reproducing a bug from a production token by re-signing the same payload with a known dev secret to compare behavior.
  • Demonstrating JWT structure in a workshop or onboarding session: type a payload, sign it, decode it, point at the three segments.
  • Pairing with the JWT Decoder on this site for a round-trip: generate, copy, paste into the decoder, confirm the claims read back exactly.
  • Crafting a token with deliberately invalid claims (expired exp, mismatched aud) to test that your verifier rejects them.
  • Generating a fixture token to embed in an integration test, where the test setup mints a fresh JWT before each suite.

Common pitfalls and edge cases

  • HMAC secrets are symmetric. Any party with the secret can forge tokens. Treat HS256 secrets as production credentials and never commit them to git or write them to logs. For multi-service signing, switch to RS256 or EdDSA, neither of which is exposed by this tool because private keys have no safe story in a browser.
  • Time claims are integers, not strings. "exp": 1735689600 is correct; "exp": "2025-01-01T00:00:00Z" is invalid per RFC 7519. The tool's Add iat+exp helper inserts the right shape automatically.
  • Trailing whitespace in the secret breaks verification. The most common false-positive bug is a copied secret with a stray newline; verify by hashing the secret directly and comparing to the verifier's view.
  • The "alg: none" attack is famous: a JWT signed with no signature can pass verifiers that do not enforce the alg allowlist. This generator does not expose alg=none, but if you are testing a verifier, manually construct a token with {"alg":"none"} and an empty signature segment to confirm it is rejected.
  • JWE is a different spec. JWT itself is unencrypted; the payload is base64url-decodable by anyone who sees the token. To encrypt the payload, use JWE (RFC 7516); the tool here only signs.
  • Header order matters for the signature. Re-encoding the same JWT with reordered header keys produces a different signature, even though the structural meaning is identical. Always sign the canonical form your verifier expects.

JWT, JWS, JWA: the standards behind the tokens

JWT (RFC 7519, 2015) is a compact, URL-safe representation of claims as a JSON object. JWS (RFC 7515) defines the signing format - the three-segment dot-separated structure. JWA (RFC 7518) enumerates the cryptographic algorithms each implementation must accept. The HS256 family uses HMAC over SHA-2, defined by FIPS 198-1. RS256 uses RSASSA-PKCS1-v1_5; ES256 uses ECDSA over P-256; EdDSA uses Ed25519 per RFC 8037. The OAuth 2.0 (RFC 6749) and OpenID Connect specs default to JWT for access tokens and ID tokens, which is why the format is everywhere in modern auth flows. The compact serialization in this tool is the most common; JWS also defines a JSON Serialization for use cases that need detached or multi-recipient signatures.

Alternatives and when they beat this tool

The Node library jsonwebtoken is the standard for server-side signing and verification, with a richer claim helper API and built-in clock-skew tolerance. jose on npm covers the full JOSE spec family (JWE, JWK, JWKS) and is the right pick when you need asymmetric signing or encryption. PyJWT is the equivalent in Python, with explicit algorithm allowlists. The CLI tool jwt-cli (Rust) signs and decodes from a shell. jwt.io is the famous web reference, but it sends the secret to a remote service, which is why this tool exists locally. Use this generator when you want a quick HS256 token in the browser, want to avoid pasting a secret into a remote site, and pair it with the local JWT Decoder for a fully on-device round-trip.

Frequently Asked Questions

Which algorithms are supported?

HS256, HS384 and HS512 - HMAC over SHA-2 with the same secret used to verify. RS256 and ES256 are deliberately excluded because they require a private key, which has no safe story in a browser tool. For asymmetric signing use a server library such as jose, jsonwebtoken or pyjwt.

Where is the secret stored?

Nowhere persistent. The secret lives in component state for the duration of the page and is dropped on reload or Clear. There is no fetch call or analytics beacon for the value you type. Use a staging secret when demonstrating this page.

How long should the secret be?

RFC 7518 says the HMAC key must be at least the size of the hash output - 32 bytes for HS256, 48 for HS384, 64 for HS512. Shorter keys still work arithmetically but reduce signature strength against brute-force search. Use a random key from a CSPRNG for production tokens.

How do I add an expiration claim?

Use the "Add iat + exp" helper to insert standard time claims on the current payload. iat is the issued-at time and exp is the expiry, both as Unix-seconds integers per RFC 7519. The default helper sets exp one hour after iat.

Can I round-trip with the JWT decoder on this site?

Yes. Generate a token here, copy it, open the JWT Decoder and paste - the header, payload and signature read back identically. The decoder cannot verify the signature because that needs the secret you supplied, which is correct behaviour for a privacy-respecting tool.

More Developer Tools