Skip to content
Advertisement

JWT Generator

Build and sign HS256 JSON Web Tokens from a header, payload, and secret.

Generator Crypto

For development and debugging

Header, payload, and secret stay in this tab — nothing is uploaded or stored. Sign production tokens inside your backend, where the secret actually lives.

Held in memory only — never saved, logged, or sent.

Signed token (live)
Fix the errors above to see the signed token.

Settings

How JWT Generator works

A JSON Web Token is three Base64URL-encoded parts joined by dots: a header, a payload, and a signature. The header names the algorithm and token type; the payload carries the claims; the signature binds the two together so that neither can be altered without detection.

With HS256 the signature is HMAC-SHA-256 over the exact ASCII string formed by the encoded header, a dot, and the encoded payload — computed with a shared secret. Anyone holding that secret can both create and verify tokens, which is what makes HMAC symmetric and why the secret must never reach a client.

Claims fall into registered names defined by RFC 7519 and whatever custom names your application needs. The registered ones matter most: exp bounds the token’s lifetime, iat records when it was issued, nbf marks the earliest time it may be accepted, and sub, iss, and aud identify the subject, issuer, and intended recipient. All three time claims are seconds since the Unix epoch, not milliseconds.

Base64URL is not encryption. Anyone who receives the token can read the payload — the signature guarantees integrity and authenticity, not confidentiality. Never put a password, a card number, or anything else you would not print on a postcard into a JWT.

Reference

  • JWT = base64url(header) + "." + base64url(payload) + "." + base64url(signature)
  • HS256 signature = HMAC-SHA-256(secret, base64url(header) + "." + base64url(payload))
  • exp / iat / nbf are NumericDate: seconds since 1970-01-01T00:00:00Z
  • Base64URL replaces + with -, / with _, and strips = padding

How to use this generator

  1. Set the header

    Leave it as {"alg":"HS256","typ":"JWT"} unless you have a reason to change it. The alg value must match how you sign.

  2. Write the payload

    Add your claims as JSON. Include exp for expiry and iat for issue time — most libraries reject tokens missing them.

  3. Provide a secret

    Use at least 32 bytes of random data for HS256. A short, guessable secret is the weakest link in the whole scheme.

  4. Copy the signed token

    The three-part token is produced live. Paste it into an Authorization: Bearer header to test your API.

Worked examples

A short-lived API test token

Given
{"sub":"user-42","iat":1786500000,"exp":1786503600} with a 32-byte secret
Result
A token valid for exactly one hour

exp minus iat is 3600. Keep test tokens short-lived so a leaked one in a shell history expires on its own.

Adding a role claim

Given
{"sub":"user-42","role":"admin","exp":1786503600}
Result
A token your middleware can authorise on without a database lookup

Custom claims are fine, but remember they are readable by the holder — put authorisation decisions behind server checks, not client trust.

Reproducing a signature mismatch

Given
The same payload signed with secret "dev" and verified with secret "prod"
Result
Verification fails, payload decodes fine

This is the normal shape of a JWT bug: the token looks structurally perfect and still fails, because HMAC depends on the exact secret bytes.

When to use it

  • Creating a token by hand to test an API endpoint’s authentication middleware.
  • Reproducing a production token’s claim structure locally to debug an authorisation failure.
  • Generating fixtures with specific exp or nbf values to test expiry and not-before handling.
  • Checking that your service rejects tokens signed with the wrong secret or a tampered payload.
  • Learning the exact byte-level structure of a JWT while implementing one.

Things to watch out for

  • The payload is encoded, not encrypted. Assume every claim is public to anyone holding the token.
  • HS256 secrets should be at least 256 bits of randomness. Human-chosen secrets are brute-forceable offline once an attacker has one token.
  • Never accept the alg value from the token itself when verifying. Pin the expected algorithm server-side — the classic "alg: none" and RS256-to-HS256 confusion attacks both exploit trusting it.
  • Times are in seconds. Passing JavaScript’s Date.now() directly gives milliseconds and produces tokens that appear to expire tens of thousands of years from now.

Frequently asked questions

Is my secret sent to a server?

No. Signing uses the Web Crypto API in your browser, and neither the secret nor the resulting token is transmitted. That said, tokens you generate here are still real credentials — handle them accordingly.

How long should my secret be?

For HS256, at least 32 random bytes. The security of HMAC rests entirely on the secret’s entropy, and a dictionary word can be cracked offline in seconds once someone has a single token signed with it.

Why does my API reject a token that looks correct?

The usual causes are a secret mismatch, exp or iat written in milliseconds instead of seconds, a missing aud or iss claim that the server requires, or clock skew between the signer and the verifier.

Can I use RS256 instead of HS256?

This tool signs with HS256, the symmetric HMAC algorithm. RS256 uses an asymmetric key pair so that verifiers need only the public key — the right choice when tokens are verified by parties you do not want to be able to mint them.

Should I put sensitive data in the payload?

No. Base64URL is trivially reversible, so every claim is readable by anyone holding the token. Store an opaque identifier in the token and keep the sensitive data server-side.

What is the difference between exp and nbf?

exp is the latest time a token may be accepted; nbf is the earliest. A token with nbf in the future is valid but not yet usable, which is occasionally useful for scheduled access grants.

All developer tools