JWT Generator

Create signed JSON Web Tokens with HMAC-SHA256/384/512

{{ error }}

What is a JWT?

A JSON Web Token (JWT, RFC 7519) is a compact, signed container for JSON data. It has three Base64URL-encoded parts separated by dots: header (algorithm), payload (claims) and signature. JWTs are used for stateless API authentication (bearer tokens), OAuth/OpenID Connect and single sign-on.

Which algorithm?

HS256/384/512 are symmetric HMAC algorithms — sender and receiver share the same secret. Simple and fast, fitting for internal APIs. For public APIs, asymmetric RS256 or ES256 (public/private key) is preferred — both supported by Web Crypto API but with more complex key management. 'none' (unsigned) should never be used in production.

Important security notes

  • Never put secret data in the payload — JWTs are signed, not encrypted
  • Secret must be at least as long as the hash output (256/384/512 bits)
  • Always set exp/nbf claims and validate on receipt

What technically happens during signing

Building a JWT happens in three steps. First, header and payload are each serialized as JSON. Then each part is Base64URL-encoded (RFC 4648 §5) — the URL-safe flavour with -/_ instead of +//, without padding =. The two encoded strings produce the signing input as base64url(header) + "." + base64url(payload). Only this complete string is signed, not the raw JSON. That matters: two semantically identical but differently serialized headers (different key order, whitespace) yield different signatures — when comparing tokens, you must compare canonical forms, not parsed objects.

The HMAC family (HS256/384/512) uses a shared key and is symmetric — anyone who can sign can also verify. Practical for monolithic apps with a single backend, problematic as soon as multiple services need to verify, because the secret has to live in each one. RS256 (RSA-PKCS1-v1.5 + SHA-256, RFC 3447) and ES256 (ECDSA on P-256) are asymmetric: the issuer holds the private key, all verifiers only need the public key — usually distributed via a JWKS endpoint at /.well-known/jwks.json. RFC 8037 explicitly recommends EdDSA (Ed25519) for new systems: no padding tricks, much shorter signatures (~88 bytes Base64 vs. 256 bytes for 2048-bit RSA) and constant-time verification.

alg: none is permitted by the spec and has caused years of security incidents. RFC 8725 ("JWT Best Current Practices") is explicit: never accept alg: none. The verifier should enforce a strict algorithm whitelist, ideally one concrete algorithm per endpoint. The second practical recommendation: set typ to JWT, only use cty for nested JWS/JWE. Third: use kid once more than one key is in flight so rotation becomes possible. The output of this generator is exactly what you put into the Authorization header: Authorization: Bearer <token>.

Build a JWT in five steps

Build a production-ready token that mainstream verifiers will accept.

  1. Define the header: {"alg":"HS256","typ":"JWT"} for simple setups or {"alg":"RS256","typ":"JWT","kid":"key-2024-01"} with key rotation.
  2. Fill the payload with standard claims: iss (who issued it), sub (user id), aud (which service may use the token), iat, exp (Unix seconds).
  3. Add custom claims: roles, tenant_id, scope. No passwords, no PII — JWT is not encrypted.
  4. Choose a secret or private key. For HS256 at least 32 random bytes, base64-encoded — e.g. openssl rand -base64 32. Never "secret" or "changeme" in production.
  5. Sign the token, copy it and pass it via the HTTP header: Authorization: Bearer eyJhbGci.... The receiver verifies with the same secret or the matching public key.

Typical tokens for real-world use cases

These examples show payloads as they are generated by real production systems.

  • Access token for a REST API: {"sub":"u_42","iat":1700000000,"exp":1700003600,"aud":"api.example.com","scope":"read:profile write:posts"} — valid for one hour.
  • Refresh token: {"sub":"u_42","iat":...,"exp":...+2592000,"typ":"refresh","jti":"uuid-..."} — valid for 30 days, with jti for revocation.
  • Magic link / password reset: {"sub":"u_42","purpose":"reset","iat":...,"exp":...+900,"jti":"..."} — valid for 15 minutes, single-use via jti blacklist.
  • Service-to-service token: {"iss":"billing-svc","sub":"billing-svc","aud":"users-svc","iat":...,"exp":...+60} — very short-lived, identifies the calling service.
  • OIDC ID Token: {"iss":"https://auth.example.com","sub":"user-42","aud":"client-id","email":"[email protected]","nonce":"...","iat":...,"exp":...} — identity proof for login.

What to watch out for when signing

First point: the HS256 secret must be cryptographically random. A dictionary word cracks in seconds — generate with openssl rand -base64 32 or crypto.randomBytes(32). Second point: short exp windows. Access tokens should live at most 15 minutes, ID tokens at most one hour, refresh tokens may live longer but then need revocation. Third point: token size. Every byte lands in every HTTP header. Above 1 KB some proxies and load balancers reply with 431 Request Header Fields Too Large. Fourth point: this generator only offers alg: none for demos — never accept it in production. Fifth point: the cryptographic operations here run in the browser via the Web Crypto API; the secret never leaves your device but is held in JavaScript memory. Avoid this tool for production secrets on unprotected machines.

Frequently asked questions about generating JWTs

How do I generate a secure HS256 secret?
Use openssl rand -base64 32 or node -e "console.log(require('crypto').randomBytes(32).toString('base64'))". Minimum length: 256 bits (32 bytes) for HS256, 384 bits for HS384, 512 bits for HS512. Store it in a secret manager like Vault, AWS Secrets Manager or Doppler — never in a Git repo.
Should I use HS256 or RS256?
Use HS256 when issuer and verifier are the same trusted codebase. Use RS256 (or better EdDSA) as soon as multiple services or third parties need to verify — you then distribute the public key via JWKS and keep the private key with the issuer. Auth0, Cognito and Keycloak default to RS256.
Which claims are mandatory?
RFC 7519 does not require any claim formally. In practice you should always set: iss, sub, aud, iat, exp. For revocation add jti. The OIDC spec additionally requires nonce for the authorization-code flow with implicit parts.
How long should exp be?
Rule of thumb: access tokens 5–15 minutes, ID tokens 1 hour, refresh tokens 7–30 days. Shorter is safer because a captured token becomes worthless faster. Very short windows require a working refresh mechanism, otherwise the user keeps hitting login dialogs.
Can I encrypt a JWT?
Yes, with JWE (JSON Web Encryption, RFC 7516) instead of JWS. Instead of two dots a JWE has five: header.encryptedKey.iv.ciphertext.tag. In practice few APIs need JWE — the more common setup is TLS (encrypts the entire transport) plus a signed but unencrypted JWS.
Does my secret leave the browser here?
No. Signing happens entirely in the browser via the Web Crypto API (crypto.subtle.sign). No request is sent to any server, the secret exists only in your RAM. You can load the page offline and it still works. Even so: only enter production secrets on a device you fully trust.

Related tools