JWT (JSON Web Token) is the auth standard for modern APIs. Every OAuth flow, every Auth0 / Cognito / Firebase Auth integration, every internal microservice that needs to pass identity around — all of them use JWTs. The token looks like gibberish: eyJhbGciOi…. Decoded, it’s three small JSON objects that say “this user, signed by this issuer, valid until this time”. Decoding is non-secret — anyone with the token can read its contents. Verifying the signature requires the secret. Both operations are routine for backend developers and frequently need a quick lookup tool.
Our JWT encoder/decoder takes any JWT string and renders the header + payload as pretty-printed JSON. Optionally paste the secret to verify the signature, or build a fresh token from custom JSON. Everything runs in your browser via the Web Crypto API; the token and secret never transmit. This guide explains JWT structure, the differences between HS256 and RS256, and the security gotchas that have produced real-world authentication failures.
JWT structure — three Base64-URL parts joined by dots
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUiLCJpYXQiOjE2NjcwMDAwMDB9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
↑ header ↑ payload ↑ signature
{"alg":"HS256"} {"sub":"1234567890","name":"Jane","iat":1667000000}
- Header: the algorithm used (HS256, RS256, etc.) and the token type. Always JSON.
- Payload: the claims — user ID, scopes, issued-at, expiry, custom application data. The actual identity assertion.
- Signature: a cryptographic signature of
header.payloadusing either a shared secret (HS256) or the issuer’s private key (RS256). This is what makes the token tamper-evident.
Standard claims every JWT might include
| Claim | Meaning |
|---|---|
sub |
Subject — usually the user ID |
iss |
Issuer — who created the token |
aud |
Audience — who the token is for |
exp |
Expiry — Unix timestamp after which the token is invalid |
iat |
Issued-at — Unix timestamp of token creation |
nbf |
Not-before — token isn’t valid until this time |
jti |
JWT ID — unique identifier for revocation lists |
Beyond the standard claims, applications add custom claims (scopes, roles, email, anything else). Decoding a token reveals all claims; this is why JWTs should never carry secrets.
HS256 vs RS256 — choosing the right algorithm
- HS256 (HMAC-SHA-256): uses a shared secret known to both signer and verifier. Simpler, faster, smaller signatures. Right when one service signs and the same service verifies. Wrong when verification needs to happen on multiple machines without sharing a secret.
- RS256 (RSA + SHA-256): uses asymmetric crypto. Issuer holds a private key; verifiers use the public key. Right for any “sign here, verify everywhere” pattern (Auth0, Firebase Auth, Google OAuth all use RS256). The public key can be distributed freely.
- ES256 (ECDSA): elliptic-curve variant of RS256. Smaller signatures, faster signing, equivalent security. Increasingly common in IoT and mobile contexts.
The rule of thumb: HS256 for monolithic apps where one service signs and verifies. RS256 for anything multi-service, distributed, or where third parties need to verify.
How to use the browser JWT decoder
- Open the JWT encoder/decoder
- Paste your JWT into the input. Header and payload appear as pretty-printed JSON instantly
- Optional: paste the signing secret (HS256) or public key (RS256) to verify the signature. Result shows ✓ valid or ✗ invalid
- Switch to Encode mode to build a new token from custom JSON
- Copy any decoded part with the per-section copy buttons
Real-world JWT security mistakes
- The “alg: none” attack. Some libraries trust the algorithm specified in the header. Setting it to “none” tells the library to skip signature verification. Always specify the expected algorithm at verification time.
- Confusing HS256 with RS256. If a service expects RS256 but accepts HS256 with the public key as the secret, attackers can forge tokens. Always pin the algorithm.
- Leaving secrets in JWT payloads. JWTs are encoded, not encrypted. Anyone with the token reads the payload. Never put passwords, API keys, or PII in claims.
- Long expiry times. A 90-day JWT can’t be revoked without maintaining a denylist. Keep
expshort (15-60 minutes) and use refresh tokens for sustained sessions. - Using HS256 with weak secrets. A 16-byte secret is brute-forceable. Use 32+ bytes (256 bits) of randomness for HS256 secrets.
Decoding JWT in code
// Node.js (jsonwebtoken — most common)
import jwt from "jsonwebtoken";
const decoded = jwt.decode(token); // unverified
const verified = jwt.verify(token, secret); // throws if invalid
// Browser (jose — modern, no deps)
import * as jose from "jose";
const decoded = jose.decodeJwt(token);
const { payload } = await jose.jwtVerify(token, await jose.importJWK(jwk));
// Python (PyJWT)
import jwt
decoded = jwt.decode(token, secret, algorithms=["HS256"])
// Manual decode (browser, no library)
const [header, payload] = token.split(".").slice(0, 2)
.map(seg => JSON.parse(atob(seg.replace(/-/g, "+").replace(/_/g, "/"))));
When NOT to use JWT
- For session storage. Sessions you need to revoke instantly are better as opaque session IDs in a database. JWT revocation requires a denylist that defeats the stateless benefit.
- For sensitive payload data. Anyone with the token reads the claims. Store sensitive data server-side and reference by ID in the JWT instead.
- For very long expiry. If your tokens last weeks, you’ve reinvented session storage with extra steps. Use refresh tokens with short-lived JWTs.
- When you need cookie-based CSRF protection. JWTs in localStorage are vulnerable to XSS; in cookies they’re vulnerable to CSRF. Each pattern has trade-offs to design around.
Frequently asked questions
Is JWT encrypted?
Standard JWT (JWS) is signed but not encrypted — anyone with the token can decode and read the payload. JWE (JSON Web Encryption) is the encrypted variant, much less common. Don’t put secrets in JWT claims.
Can I decode a JWT without the secret?
Yes. The header and payload are Base64-URL encoded — anyone can decode them. The secret is only needed to verify the signature (prove the token wasn’t forged) or to create a new token. Decoding without verification is fine for inspection but never trust an unverified JWT in production.
How long should a JWT expire?
15-60 minutes for access tokens. Pair with a refresh token (longer expiry, revocable, server-side stored) for sustained sessions. Short access-token expiry limits damage if a token is leaked.
Is my JWT sent to your server when I decode it?
No. Decoding happens entirely in your browser via the Web Crypto API and JavaScript Base64 decoding. The token, secret (if you paste one), and decoded output all stay on your device. Verify in DevTools Network tab — no requests during decoding.
What’s the difference between HS256 and RS256?
HS256 uses a shared secret known to signer and verifier (symmetric). RS256 uses an RSA key pair where the issuer holds the private key and verifiers use the public key (asymmetric). Use HS256 for one-service contexts, RS256 for distributed/multi-service auth.
Can I edit a JWT and re-sign it?
Yes — switch to Encode mode, edit the header or payload JSON, paste the secret, click Sign. The output is a new valid JWT. Useful for testing token-validation logic with custom payloads.
Related tools and guides
- JWT Encoder/Decoder
- Base64 Encoder/Decoder
- SHA-256 Hash Generator
- JSON Tree Viewer
- Password Generator — for HS256 secrets
- All coding tools
![JWT Decoder Online: Inspect Tokens in Browser [2026]](https://simpletool.io/blog/wp-content/uploads/2026/05/jwt-decoder-online.png)
![URL Slug Generator: SEO-Friendly URLs in Seconds [2026]](https://simpletool.io/blog/wp-content/uploads/2026/05/url-slug-generator.png)
![HTML Minifier: Compress HTML Safely in Browser [2026]](https://simpletool.io/blog/wp-content/uploads/2026/05/html-minifier.png)
![Base64 Encoder Decoder: Text & Files in Browser [2026]](https://simpletool.io/blog/wp-content/uploads/2026/05/base64-encoder-decoder.png)
![RGB to HEX Converter: Convert Any Color [2026]](https://simpletool.io/blog/wp-content/uploads/2026/05/rgb-to-hex-converter.png)
![Barcode Generator: Code 128, EAN-13, UPC, ITF [2026]](https://simpletool.io/blog/wp-content/uploads/2026/05/barcode-generator.png)
![CSS Minifier: Shrink Stylesheets 30–45% in Browser [2026]](https://simpletool.io/blog/wp-content/uploads/2026/05/css-minifier.png)
![Random Name Picker & List Randomizer Online [2026]](https://simpletool.io/blog/wp-content/uploads/2026/05/list-randomizer.png)
![Blur Face Online: Photo Censor in Browser [2026]](https://simpletool.io/blog/wp-content/uploads/2026/05/blur-face-censor.png)
![HTML Formatter: Beautify HTML with Prettier [2026]](https://simpletool.io/blog/wp-content/uploads/2026/05/html-formatter.png)