Skip to content
JSON Tidy

JWT generator and encoder

Write the header and claims, sign them with a secret or a private key, and copy the token. It’s meant for testing, like calling your own API without going through a login, or checking how your app handles a token with a different role. The signing happens right here in your browser, and your keys are never sent anywhere.

HS algorithms sign and verify with one shared secret. RS, PS, ES, and EdDSA sign with a private key, and anyone with the public key can verify.

Signing key

Secret encoding

Your keys never leave this page, but stick to test keys anyway. Never paste a production signing key into a website.

Choosing an algorithm

Use whatever your API expects. If you’re not sure, paste a real token from the same system into the JWT decoder and look at alg in its header.

HS256 is the common choice when one service both creates and checks the tokens, using a shared secret. RS256 and ES256 sign with a private key instead. They’re used when the tokens are checked somewhere else, by a separate API or another company’s service, because those only need the public key and can’t create tokens of their own.

Setting the claims

The payload is ordinary JSON. Here’s a typical one:

{
  "sub": "user_123",
  "role": "viewer",
  "iss": "https://auth.example.com",
  "aud": "orders-api",
  "iat": 1790640000,
  "exp": 1790643600
}

sub is who the token is about, usually a user ID. iat and exp are when it was issued and when it expires, in seconds since January 1, 1970. Seconds, not milliseconds, which is an easy mistake if you’re used to Date.now().

If your API checks iss (who issued the token) or aud (who it’s meant for), they have to match exactly, so copy them from a real token. Beyond that, add whatever your app reads, like a role or plan that controls what the user can do.

Don’t put anything private in the payload. A JWT is signed, not encrypted, so anyone who gets hold of the token can decode it and read every claim, no key needed. It also rides along with every request, so it’s worth keeping short.

Testing expired tokens and permissions

To check that your API turns away expired tokens, choose Expired an hour ago and create the token again. To test permissions, change role and sign again. If you already have a token you want to tweak, paste it into the decoder and choose Edit and re-sign. It opens here with the same header and claims, and the secret too if you entered one.

Open in decoder does the reverse. It shows your new token decoded, with its key already filled in, so you can see the signature verify.

Secrets and keys

Generate secret makes a random 64-character secret, long enough for HS256, HS384, and HS512. Generate a test key pair makes a new private and public key for the algorithm you picked. The public key is what your API needs to check the tokens.

Signing happens in your browser with its built-in Web Crypto API, and nothing you type is sent anywhere. Even so, don’t paste a production signing key into any website, this one included. Whoever has that key can make tokens your API will accept.

Creating a JWT in code

// Node.js, with jose (npm install jose)
import { SignJWT } from "jose";
const secret = new TextEncoder().encode(process.env.JWT_SECRET);
const token = await new SignJWT({ role: "viewer" })
  .setProtectedHeader({ alg: "HS256" })
  .setSubject("user_123")
  .setIssuedAt()
  .setExpirationTime("1h")
  .sign(secret);

# Python, with PyJWT (pip install pyjwt)
import jwt, time
now = int(time.time())
token = jwt.encode(
    {"sub": "user_123", "role": "viewer", "iat": now, "exp": now + 3600},
    secret, algorithm="HS256")

These are handy for scripts and tests. In a real app, tokens should come from your login server or identity provider rather than being built by hand.

Have a token you want to check? Use the JWT decoder. For how the header, claims, and signature fit together, read What is a JWT?