When Do You Actually Generate a JWT Yourself?
In production, your identity provider (Auth0, Okta, Firebase Auth, AWS Cognito, Keycloak, or your own auth server) generates JWTs. You almost never hand-craft one. So why generate a JWT with an online tool?
- Testing your verification code. You need a token with specific claims to unit-test the middleware that rejects expired tokens, missing scopes, or wrong audiences.
- Mocking an auth response. You are building the frontend before the auth backend exists and need a valid-looking token to develop against.
- Learning JWT internals. Generating a token by hand teaches you exactly what each segment does and why the signature depends on the header + payload.
- Interop testing. You need a token signed with a specific algorithm to verify that a library or gateway accepts it.
None of these use cases require a real production secret. Use a throwaway secret and a payload with fake user data.
Anatomy of a Generated JWT
1. Header
Two required fields: alg (signing algorithm) and typ (always "JWT").
{
"alg": "HS256",
"typ": "JWT"
}Optional: kid (key id — used to select the right verification key when you rotate keys via a JWKS endpoint).
2. Payload — Standard Claims
The seven registered claims from RFC 7519:
iss— issuer (URL of your auth server)sub— subject (user id)aud— audience (API identifier)exp— expiry (Unix timestamp)nbf— not before (Unix timestamp)iat— issued at (Unix timestamp)jti— unique token id
Add custom claims freely: role, scope, tenant_id. Namespace custom claims (https://myapp.com/role) to avoid collisions with other systems.
3. Signature
For HS256, the signature is HMACSHA256(base64url(header) + "." + base64url(payload), secret). Any party with the secret can verify or forge the token — HS256 is symmetric.
For RS256, the signature is an RSA signature over the same input using the private key. Only the private key can sign; anyone with the public key can verify. RS256 is the right choice for public APIs where you cannot trust every verifier with the signing secret.
Generating a JWT in Code — Node.js Example
The industry-standard jsonwebtoken library on npm:
const jwt = require('jsonwebtoken');
const secret = process.env.JWT_SECRET; // 32+ random bytes
const now = Math.floor(Date.now() / 1000);
const token = jwt.sign({
sub: 'user_42',
role: 'admin',
iat: now,
exp: now + (15 * 60), // 15 minutes
}, secret, {
algorithm: 'HS256',
issuer: 'https://auth.example.com',
audience: 'https://api.example.com',
jwtid: crypto.randomUUID(),
});Generating a JWT in Python — Example
Using PyJWT:
import jwt, os, time, uuid
secret = os.environ['JWT_SECRET']
now = int(time.time())
token = jwt.encode({
'iss': 'https://auth.example.com',
'sub': 'user_42',
'aud': 'https://api.example.com',
'role': 'admin',
'iat': now,
'exp': now + (15 * 60),
'jti': str(uuid.uuid4()),
}, secret, algorithm='HS256')Security Rules for Every Generated JWT
- Short expiry. Access tokens should live 5–15 minutes. Use refresh tokens for longer sessions.
- Strong secret. For HS256, use 32+ random bytes from a CSPRNG. Never use a password-like string.
- No PII in payload. JWT payloads are Base64-encoded, not encrypted. Anyone who intercepts the token sees the claims.
- Bind to audience. Always set
audand enforce it on the verifier. Prevents a token issued for one API being replayed against another. - Include jti for revocation. If you need to invalidate tokens before expiry, keep a small blocklist keyed by
jti. - Rotate keys. Generate a new signing key every 90 days. Publish the new public key via JWKS and phase out the old one.
Common Mistakes When Generating Tokens
- Timestamps in milliseconds instead of seconds. JWT
exp/iat/nbfare all Unix seconds. PassingDate.now()instead ofMath.floor(Date.now() / 1000)creates tokens that expire in the year 55000. - Missing exp. A JWT without
explives forever. Always set one. - Reusing the same jti. If you copy-paste an example token generator without changing
jti, revocation lists cannot distinguish tokens. - Signing with the empty string as secret. Silently succeeds in some libraries. Any attacker who tries the empty string as key will validate every token.
- Trusting the alg field on verify. The verifier must specify which algorithms it accepts. Reading
algfrom the incoming token and using that to pick the verification method is the classic algorithm-confusion attack.
Key Facts
- Output format:
- header.payload.signature (three Base64URL segments)
- Signing:
- HS256 (HMAC-SHA256) or RS256 (RSA-SHA256) via SubtleCrypto
- Runs in:
- Your browser — secret never uploaded
- Standards:
- RFC 7519 (JWT), RFC 7515 (JWS), RFC 7517 (JWK)
- Use case:
- Testing only — never generate production tokens on an online tool
Related JWT Tools
- JWT Decoder Online — decode any JWT to see its claims
- Verify JWT Signature — HS256/RS256 signature verification walkthrough
- JWT Decoder in JavaScript — atob() + jose library patterns
- JWT Decoder in Python — PyJWT decode & verify patterns
- Base64 Encode — encode strings to Base64/Base64URL
- Hash Generator — compute SHA-256, HMAC, MD5 locally