Back Security

JWT Generator

Generate signed JSON Web Tokens with custom headers, payload claims and HMAC-SHA signing. Your secret key never leaves your browser — signing uses the Web Crypto API client-side.

Last updated: May 2026 · Reviewed by FreeDevTool security engineering team
Generated JWT will appear here...
Copied!

How to use the JWT generator

Generate JWTs for local testing, debugging auth flows, or generating signed payloads in scripts. Set custom claims, pick HMAC-SHA256 signing, and copy the token. This generator is for development only — don't use the output as production secrets, and never paste real production keys here.

Common mistakes to avoid

JWTs in production — the spec, the algorithms, and the attacks you need to know

JSON Web Tokens are the connective tissue of modern auth. OAuth 2.0 access tokens, OpenID Connect ID tokens, AWS Cognito sessions, Auth0 sessions, Firebase Auth, Cloudflare Zero Trust, and every framework's "auth helper" all hand you JWTs. The spec is small (RFC 7519) and the format is elegant — but the historical CVEs against JWT implementations are extensive, and most of them are caused by misuse rather than spec flaws. This guide walks through the structure, the algorithm choices that matter, the alg=none and key-confusion attacks every junior backend engineer needs to know about, and the rotation patterns that production systems actually use.

The structure — three Base64URL parts joined by dots

A JWT is header.payload.signature, all Base64URL-encoded:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0IiwibmFtZSI6IkpvaG4iLCJpYXQiOjE1MTYyMzkwMjJ9.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Decoded:

The payload is not encrypted. Anyone with the token can read its contents. The signature only proves the token has not been modified since it was issued.

Standard claims (RFC 7519) — what each one is for

ClaimNameTypePurpose
issIssuerstringWho signed the token. Verifiers should check this.
subSubjectstringThe subject the claim is about (typically user ID).
audAudiencestring or arrayWho the token is for. Reject tokens not addressed to your service.
expExpirationUnix secondsToken rejected after this time. Required for any non-trivial use.
nbfNot BeforeUnix secondsToken rejected before this time.
iatIssued AtUnix secondsWhen the token was issued.
jtiJWT IDstringUnique identifier for the token (replay protection).

Algorithm choices — pick deliberately

AlgorithmTypeKeyWhen to use
HS256HMAC + SHA-256Shared secret (≥ 256 bits)Single service signs and verifies its own tokens.
HS384 / HS512HMAC + SHA-384 / 512≥ 384 / 512 bitsSame as HS256 with stronger hash.
RS256RSA + SHA-2562048-bit private keyIssuer signs, multiple consumers verify with the public key.
ES256ECDSA P-256 + SHA-256256-bit ECC keySame as RS256, smaller signatures, faster on mobile.
EdDSA / Ed25519Edwards-curve DSA256-bit Ed25519 keyModern default for new asymmetric setups (RFC 8037).
PS256RSA-PSS + SHA-256RSA keyRSA signatures with probabilistic padding (modern variant).
noneUnsignedNoneNever accept. Spec allows it; safe libraries reject by default.

The fork in the road is symmetric vs asymmetric:

The classic JWT attacks — and how to defend

  1. alg: none — the attacker resigns the token with alg: "none" and sends it. Vulnerable libraries skip signature verification because the spec technically allowed unsigned tokens. Defence: hard-code an allow-list of accepted algorithms; reject everything else, especially "none".
  2. Algorithm confusion (RS → HS) — server is configured for RS256 but accepts any algorithm. Attacker takes the public key (which is, well, public) and uses it as the HMAC secret with HS256. The signature now verifies because the library treats the public key as a shared secret. Defence: tie the algorithm to the key type — never let HS algorithms verify with an RSA public key.
  3. Key confusion via jku / jwk headers — attacker sets a header that points the server at an attacker-controlled JWKS URL. Defence: never trust jku / jwk / x5u / kid values from the token; resolve keys from a server-side allow-list.
  4. Long-lived tokens — leaked tokens give permanent access if they never expire. Defence: short-lived access tokens (5–60 min) + refresh tokens.
  5. Replay across services — token signed for service A is replayed against service B (which trusts the same issuer). Defence: enforce aud claim validation per service.
  6. Information leakage — sensitive data in payload because "it's signed". JWTs are not encrypted. Defence: keep payload minimal; for confidential data, use JWE (encrypted JWT) or store server-side and reference by ID.

Token rotation — the production pattern

Long-lived JWTs are an operational liability. The pattern that scales:

  1. Access token: short-lived JWT (5–15 minutes). Sent on every request. Stateless verification.
  2. Refresh token: opaque random string (not a JWT). Long-lived (days to weeks). Stored server-side, can be revoked. Used to mint new access tokens.
  3. Refresh-token rotation: each refresh issues a new refresh token; the old one is invalidated. Detects token theft when a stolen refresh token is used after the legitimate one.
  4. Key rotation: sign new tokens with key 2; keep verifying old tokens with key 1 until they all expire. Use the kid header so verifiers know which key to use.

Verification in 6 languages — the safe way

Node.js (jsonwebtoken):
const jwt = require('jsonwebtoken');
const decoded = jwt.verify(token, secret, {
  algorithms: ['HS256'],   // explicit allow-list — defends against alg=none
  issuer: 'https://issuer.example.com',
  audience: 'my-service'
});
Python (PyJWT):
import jwt
decoded = jwt.decode(
  token, secret,
  algorithms=['HS256'],
  issuer='https://issuer.example.com',
  audience='my-service'
)
Go (golang-jwt/jwt v5):
parser := jwt.NewParser(jwt.WithValidMethods([]string{"HS256"}))
token, err := parser.Parse(tokenStr, func(t *jwt.Token) (any, error) {
    return secret, nil
})
Java (Auth0 java-jwt):
Algorithm alg = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(alg)
    .withIssuer("https://issuer.example.com")
    .withAudience("my-service")
    .build();
DecodedJWT jwt = verifier.verify(token);
Rust (jsonwebtoken crate):
use jsonwebtoken::{decode, DecodingKey, Validation, Algorithm};
let mut v = Validation::new(Algorithm::HS256);
v.set_audience(&["my-service"]);
v.set_issuer(&["https://issuer.example.com"]);
let token = decode::<Claims>(token, &DecodingKey::from_secret(secret), &v)?;
PHP (firebase/php-jwt):
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$decoded = JWT::decode($token, new Key($secret, 'HS256'));

JWE vs JWS — when you need encryption, not just signing

JWS (JSON Web Signature) is what most people mean when they say "JWT" — payload is signed but readable. JWE (JSON Web Encryption, RFC 7516) wraps the payload in encrypted form so it cannot be read without the key. Use JWE when:

JWE has 5 parts (header.encrypted-key.iv.ciphertext.tag), is roughly 50% larger than JWS, and adds complexity. Default to JWS unless you have a specific reason for encryption.

Common JWT mistakes

Best JWT generator online for 2026 — what to compare

Search results for "jwt generator", "create jwt online", and "sign jwt with secret" surface a mix of single-algorithm web forms and full library playgrounds. Three things actually matter when you pick one: whether the secret/private key is sent to a server (most are), whether asymmetric algorithms (RS256, ES256, EdDSA) are supported (most aren't), and whether the tool round-trips with a decoder for verification testing. Here is how the most-used JWT generators compare in 2026:

ToolBrowser-only signingHS familyRS / ES / EdDSADecoder pairingCost
FreeDevTool JWT GeneratorYes (Web Crypto)HS256/384/512RS256, ES256, EdDSAYes (JWT Decoder)Free
jwt.io debuggerYesHS256 only by defaultRS256 (manual key paste)Same pageFree
tooltester / token.devMixed (some submit to server)HS256LimitedNoFree, ad-funded
jsonwebtoken (npm)Local installAll HSAll RS / ES / EdDSASame packageFree, OSS
jose (npm — preferred 2026)Local installAll HSAll RS / ES / EdDSA / JWESame packageFree, OSS

How do I sign a JWT with a custom secret without a server?

Pick HS256 (or HS384/HS512 if your verifier expects them), paste your shared secret into the secret field, set the header and payload JSON, and click Generate. The browser's Web Crypto API performs the HMAC-SHA computation locally — your secret never leaves the page, and the resulting token can be pasted directly into Authorization: Bearer <token> headers for local testing. For RS256 / ES256, paste a PEM-encoded private key and the same flow works asymmetrically. Security warning: never paste a production signing secret into any online tool, even client-side ones. Use HS256 generators only for local development tokens, dummy claims for unit tests, or short-lived debugging tokens with a throwaway secret.

What's the difference between HS256, RS256, and ES256?

HS256, RS256, and ES256 all produce valid JWT signatures, but they use fundamentally different cryptographic primitives.

AlgorithmFamilyKey typeBest for2026 recommendation
HS256 / HS384 / HS512Symmetric HMAC-SHAShared secret (32+ bytes)Single-service tokens, internal APIsUse HS256 minimum; HS512 if compliance requires
RS256 / RS384 / RS512Asymmetric RSA-PKCS#1 v1.5RSA key pair (2048+ bits)OIDC, federated APIs (issuer signs, consumer verifies with public key)Acceptable but slower; prefer ES256 for new systems
ES256 / ES384 / ES512Asymmetric ECDSAElliptic-curve key pair (P-256+)Modern OIDC, JWS standards, mobile-first systemsBest balance of speed + security in 2026
EdDSA (Ed25519)Asymmetric Edwards curve32-byte key pairHigh-throughput services, Curve25519 ecosystemsFastest; supported by jose, golang-jwt, jjwt
noneNO signatureNoneNEVER USEReject any token with "alg":"none" at parse time

Decision rule: same service signs and verifies → HS256. Cross-service or public verification → ES256 (preferred) or RS256 (legacy). High-throughput → EdDSA. Never accept none regardless of what the header claims.

JWT generator alternative to jwt.io — 4 reasons developers switched

  1. Asymmetric algorithms surfaced as first-class. RS256, ES256, and EdDSA in the same algorithm dropdown as HS256 — no manual key paste workflow.
  2. Standard claim quick-buttons. "Expire in 1h / 24h / 7d / 30d", "Set iat to now", "Generate jti UUID" — saves the timestamp math and prevents the "iat in the future" bug that breaks verification.
  3. Direct round-trip with the decoder. One click sends the generated token to the JWT Decoder with the same secret/key — verifies the signature end-to-end without leaving the site.
  4. No tracker pixels, no auth-product upsell. jwt.io is owned by Auth0, and the page injects Auth0 marketing prompts. This page has no commercial agenda — sign and decode, that's it.

Pair the JWT generator with the JWT Decoder for verification, the Hash Generator for HMAC payload preparation, the UUID Generator for the jti claim, and the API Authentication Guide for the broader OAuth2 / OIDC story.

Frequently Asked Questions

What is a JSON Web Token (JWT) and what are its parts?
A JWT is a compact, URL-safe token defined by RFC 7519 for securely transmitting claims between two parties. It has three Base64URL-encoded parts separated by dots: the Header (algorithm and token type), the Payload (claims like iss, sub, exp, iat), and the Signature (HMAC or RSA signature of the header and payload). JWTs are widely used in OAuth 2.0, OpenID Connect, and stateless API authentication.
How do I set an expiration time on a JWT?
The exp claim is a Unix timestamp (seconds since epoch) indicating when the token expires. To expire in 1 hour, set exp to the current time plus 3600. Common companion claims include iat (issued at — when the token was created) and nbf (not before — the token is invalid before this time). Use the quick buttons above to auto-fill these values.
Is it safe to generate JWT tokens in an online tool?
Yes, when the tool runs entirely client-side. This generator uses the browser's Web Crypto API (crypto.subtle) for HMAC-SHA signing. Your secret key and payload data never leave your machine — no data is sent to any server. For production systems, always sign tokens on the server and never embed your signing secret in client-side JavaScript code.

Browse all 50 free developer tools

All tools run in your browser, no signup required, nothing sent to a server.