JWT Generator

Build a JWT with your own header and payload and sign it with HMAC. Use it to test an endpoint, or to see what a set of claims looks like once it is encoded. The tokens are for testing; production tokens belong on your server.

Header (JSON)
Payload (JSON)
Generated Token

1 A JWT is a signed set of claims

A JSON Web Token (RFC 7519) carries claims such as a user ID and an expiry time between two parties. The signature lets the receiver check that the claims were not changed in transit. However, the payload is only Base64url-encoded, so anyone holding the token can read it.

2 Token Structure

Header

Algorithm and token type

Payload

Claims such as sub and exp

Signature

HMAC over header.payload

3 Keep production signing on the server

The jsrsasign library signs the token in this tab, so the secret is never sent to a server. Sign production tokens on your backend. A secret typed into a browser can end up in clipboard history or a screen share, and any service holding an HS256 secret can mint tokens.

How to use the JWT Generator tool

  1. Edit the Header JSON if needed. It defaults to {"alg":"HS256","typ":"JWT"}; the tool signs with the alg in the header, so HS384 and HS512 also work, but RS256 and other key-pair algorithms do not.
  2. Edit the Payload JSON with your claims, such as sub, name, iat and exp. Click Upload Payload to load claims from a .json file, or Dummy Data for a sample.
  3. Type the signing secret into the Secret Key field.
  4. Click Sign & Generate Token. The token appears in the output panel as three dot-separated parts: header, payload and signature.
  5. Click Copy to copy the token, then paste it into an Authorization: Bearer header to test your API. Clear resets everything.

How to create a signed JWT (HS256) in JavaScript, PHP and Python

JavaScript / Node.js

const { createHmac } = require("node:crypto");

// HS256 token with no dependencies
function signHS256(payload, secret) {
  const b64url = (obj) => Buffer.from(JSON.stringify(obj)).toString("base64url");
  const header = b64url({ alg: "HS256", typ: "JWT" });
  const body = b64url(payload);
  const signature = createHmac("sha256", secret).update(`${header}.${body}`).digest("base64url");
  return `${header}.${body}.${signature}`;
}

const now = Math.floor(Date.now() / 1000);
const token = signHS256(
  { sub: "1234567890", name: "John Doe", iat: now, exp: now + 3600 },
  "your-256-bit-secret"
);
console.log(token);

// With the jsonwebtoken package (npm i jsonwebtoken):
// const jwt = require("jsonwebtoken");
// jwt.sign({ sub: "1234567890", name: "John Doe" }, "your-256-bit-secret", { expiresIn: "1h" });

The hand-rolled version shows how the format works. In production, use jsonwebtoken or jose, which also handle RS256, key rotation and claim validation.

PHP (firebase/php-jwt)

<?php
// composer require firebase/php-jwt
require 'vendor/autoload.php';

use Firebase\JWT\JWT;

$payload = [
    'sub'  => '1234567890',
    'name' => 'John Doe',
    'iat'  => time(),
    'exp'  => time() + 3600,
];

$token = JWT::encode($payload, 'your-256-bit-secret', 'HS256');
echo $token, PHP_EOL;

Keep the secret in an environment variable, not in the source file.

Python (PyJWT)

# pip install PyJWT
import time
import jwt

payload = {
    "sub": "1234567890",
    "name": "John Doe",
    "iat": int(time.time()),
    "exp": int(time.time()) + 3600,
}

token = jwt.encode(payload, "your-256-bit-secret", algorithm="HS256")
print(token)

Install PyJWT, not the older unrelated package named jwt; both import as jwt and the wrong one has no encode() with this signature.

Common errors and how to fix them

Error: Invalid JSON in Header or Payload
The JSON has a trailing comma, single quotes or an unquoted key. Fix it in the editor; both boxes must contain strict JSON objects.
JsonWebTokenError: invalid signature when my API verifies the token
The API uses a different secret, or expects RS256 with a public key. Check the secret byte for byte, including whether the server Base64-decodes it before use (Auth0 style).
TokenExpiredError: jwt expired right after generating
exp must be a Unix timestamp in seconds, not milliseconds, and later than now. Date.now() returns milliseconds; divide by 1000.
Error: secretOrPrivateKey must have a value
The secret was undefined because an environment variable was not loaded. Log its length (never its value) at startup to catch this early.
The API rejects the token but this tool decodes it fine
Decoding only reads the payload. Verification also checks exp, nbf, iss and aud claims, so a missing or wrong aud fails even with a valid signature.

Good to know

A JWT is three Base64url strings joined by dots: header, payload, signature. With HS256 the signature is an HMAC-SHA256 over header.payload with a shared secret, which means any service that can verify a token can also mint one. That works for a single backend. Once several services or a third party need to verify tokens, switch to RS256 or ES256, where the issuer signs with a private key and everyone else holds only the public one.

The payload is encoded, not encrypted. Anyone holding the token can read every claim, so keep passwords, personal data and internal IDs out of it. Use the standard claim names from RFC 7519 (iss, sub, aud, exp, iat, jti) rather than inventing your own. Keep exp short, for example 15 minutes, and pair it with a refresh token, so a leaked token stops working soon after it leaks.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Guides and tutorials

Frequently Asked Questions

Which signing algorithm is used?

HS256 (HMAC with SHA-256) by default, the most widely used symmetric algorithm. The same secret signs and verifies the token. Changing alg in the header to HS384 or HS512 signs with that algorithm instead.

What claims should I include?

Usually sub (subject), iat (issued at), exp (expiry) and any application-specific claims such as roles. exp is a Unix timestamp in seconds, for example 1767225600 for 1 January 2026 at 00:00 UTC.

Can I use this for production tokens?

Use it for testing and debugging. For production, generate tokens on your server with a maintained library such as jose or PyJWT, and keep the secret out of the browser.

Why does my API reject the token?

Check four things: the secret matches, the exp claim is in the future, the API expects HS256 and not RS256, and the token was not altered after signing. Paste it into the JWT Decoder with the secret to confirm the signature.

Is the secret sent anywhere?

No. The jsrsasign library signs the token in your browser, and the page sends nothing.

Related

The JWT decoder reads a token back and verifies the signature. The HMAC generator computes that signature on its own if you want to check the math.

More Security & Hashing Tools

Browse all security & hashing tools

Copied to clipboard!