JWT Generator

Build and sign JSON Web Tokens with HMAC in your browser

What Is a JWT Generator?

A JWT generator builds a signed JSON Web Token from a header and a payload. JWTs (RFC 7519) are the de-facto standard for stateless authentication on the web: a server issues one after a successful login, the client stores it, and every subsequent request includes it in an Authorization: Bearer ... header. The server then verifies the signature instead of looking up a session.

This tool generates signed tokens using HMAC algorithms — the symmetric variants of JWS (JSON Web Signature, RFC 7515). They are appropriate when both sides of a system share a secret: a backend signs, the same backend verifies. Asymmetric algorithms (RS256, ES256) are deliberately omitted because handling a private key in a browser is a recipe for accidental disclosure; sign those tokens on the server.

Anatomy of a JWT

A JWT is three base64url-encoded segments joined with dots:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwibmFtZSI6IkFsaWNlIn0.4Z7p...
└── header ────────────────────────┘ └── payload ────────────────────────┘ └ sig ┘
  • Header — an object with the algorithm (alg) and token type (typ: "JWT"). Optionally kid (key ID) when you rotate signing keys.
  • Payload — the claims object. Any JSON you want, plus optional standard claims (iss, sub, aud, exp, nbf, iat, jti).
  • SignatureHMAC(secret, base64url(header) + "." + base64url(payload)) for HS-family algorithms.

The signature is what makes a JWT trustworthy. The payload itself is not encrypted — anyone who has the token can decode it. Don’t put passwords or PII in there.

How to Generate a JWT

  1. Paste a payload as JSON into the input panel. Use any claims you need (sub, email, role, tenant_id, etc.).
  2. Pick an algorithm in the settings panel — HS256 is the default and what 95% of systems use.
  3. Enter a secret. For HS256 the secret should have at least 256 bits of entropy (32 random bytes). For HS512 use 512 bits. Don’t reuse a low-entropy passphrase.
  4. Click Generate (or press Ctrl+Enter). The token appears in the output panel.
  5. Copy with the Copy button or Ctrl+Shift+C and paste it into a header, a .env file, an integration test, or whatever consumer needs it.

The expiration shortcuts (+15m, +1h, +1d, +7d) write a fresh exp claim into the payload before signing — convenient when you’re regenerating a test token in a hurry.

Standard Claims (RFC 7519)

ClaimPurposeExample
issIssuer — who created the token"auth.example.com"
subSubject — who the token is about"user_42"
audAudience — who the token is for"api.example.com"
expExpiration (Unix seconds)1788196800
nbfNot before (Unix seconds)1788193200
iatIssued at (Unix seconds)1788193200
jtiUnique token ID"a1b2c3..." (UUID)

Custom claims sit alongside these. A common pattern is to namespace them with a URI or a short prefix (https://example.com/role, app:plan) to avoid collisions with future standard claims.

HS256 vs HS384 vs HS512

All three are HMAC over a SHA-2 hash. They differ only in the underlying hash:

AlgorithmHashSignature lengthUse when
HS256SHA-25632 bytesDefault. What most libraries default to.
HS384SHA-38448 bytesCompliance regimes that mandate ≥384-bit hashes.
HS512SHA-51264 bytesLong-lived tokens where you want maximum margin.

In practice, HS256 is fine for almost everything. The bottleneck is usually secret entropy, not hash output length — a 16-character password is the weak link, not the algorithm.

Common Mistakes and How to Avoid Them

  • Storing JWTs in localStorage for browser apps. Any XSS leak exfiltrates the token. Prefer an HttpOnly; Secure; SameSite cookie.
  • Forgetting exp. A JWT without expiration is forever-valid. If the secret leaks, every issued token is compromised until you rotate. Always set exp.
  • Trusting alg from the client. When verifying, hard-code the expected algorithm — never read it from the incoming token’s header. This is the class of bug behind the original alg=none exploits.
  • Putting secrets in the payload. The payload is base64url, not encrypted. Anyone with the token can read it. If you need confidentiality, use JWE or just don’t put the data in the token.
  • Reusing the same secret across environments. Dev, staging, prod should each have a distinct signing key. A leaked dev key shouldn’t authenticate production users.
  • Using an HMAC secret weaker than the hash. RFC 7518 §3.2 requires the key to be at least as long as the hash output. Generate HS256 secrets with openssl rand -base64 32, not a memorable passphrase.

When NOT to Use JWTs

JWTs are great for stateless auth between services that already trust each other. They are not great when:

  • You need server-side revocation. A signed token is valid until exp. Rotating a single user out (after a password reset, account compromise, role change) requires either a denylist (which negates the stateless win) or short-lived tokens with a refresh dance.
  • Your tokens carry a lot of state. Every request ships every byte of the payload. Past ~1 KB you’re paying real bandwidth on every API call. A session cookie pointing to a Redis blob is leaner.
  • You’re protecting cookies on the same origin. A plain session cookie is simpler, easier to revoke, and avoids the entire “where do I store the JWT” foot-gun.

JWT-shaped problems → JWT. Session-shaped problems → session cookie. Both are correct in their domain.

Verifying the Token

Generation is half the workflow — you also need to verify on the receiving side. In Node.js with the jose library:

import { jwtVerify } from 'jose';

const secret = new TextEncoder().encode(process.env.JWT_SECRET);
const { payload } = await jwtVerify(token, secret, {
  algorithms: ['HS256'],   // Lock the algorithm. Never trust `alg` from the header.
  issuer: 'auth.example.com',
  audience: 'api.example.com',
});

In Python with PyJWT:

import jwt
payload = jwt.decode(
    token,
    os.environ["JWT_SECRET"],
    algorithms=["HS256"],   # explicit allowlist
    audience="api.example.com",
    issuer="auth.example.com",
)

In every language, the rule is the same: always pass an explicit algorithms allowlist when verifying. Never let the token’s own header pick the algorithm.

Frequently Asked Questions

How does this JWT generator sign tokens?

It signs tokens entirely in your browser using the Web Crypto API (SubtleCrypto). You pick an HMAC algorithm — HS256, HS384 or HS512 — and provide a secret. The tool computes the signature locally and assembles the final base64url-encoded header.payload.signature string. Your secret never leaves the browser.

Which algorithms are supported?

The three HMAC variants from RFC 7518: HS256 (HMAC-SHA-256, the most common), HS384 (HMAC-SHA-384) and HS512 (HMAC-SHA-512). Asymmetric algorithms like RS256 and ES256 are intentionally not supported here because handling private keys safely in a browser tab is risky — sign those server-side and only decode them in the browser.

What claims can I include in the payload?

Any JSON you want. The tool doesn't enforce a schema, but the standard registered claims defined in RFC 7519 are: iss (issuer), sub (subject), aud (audience), exp (expiration time, Unix seconds), nbf (not before), iat (issued at) and jti (token ID). You can also add any custom claims — role, tenant_id, scope, plan, etc.

How do I set an expiration time?

Add an exp claim with a Unix timestamp in seconds. For one hour from now, use Math.floor(Date.now() / 1000) + 3600. The tool also exposes a quick-fill button for typical lifetimes (15m, 1h, 1d, 7d). Clients and servers reject tokens whose exp is in the past, so always set this for production tokens.

Is my secret safe to type in here?

Yes. Everything runs client-side. The secret is used by the Web Crypto API in the same JavaScript context that rendered this page, never sent over the network. That said, never paste a real production secret on any third-party site you don't fully trust — for one-off testing, use a throwaway secret, then rotate it.

Can I generate a JWT with the alg=none algorithm?

No, and you shouldn't want to. The unsecured 'none' algorithm exists in the spec but it is the source of well-known authentication bypass vulnerabilities (CVE-2015-9235 and many follow-ups). If a library accepts alg=none from a client, it is broken. This tool refuses to emit alg=none on purpose.

How do I verify the JWT this tool generated?

Paste the full token into the JWT Decoder tool to inspect the header and payload. To verify the signature, run the same HMAC over the header.payload string with the same secret on the server (or in jwt.io / a library like jose / pyjwt) — if you get the same signature bytes, the token is authentic.