JSON Web Tokens are the de facto standard for authentication tokens in modern APIs. They're compact, self-contained, and URL-safe — but they're also frequently misunderstood and misused. This guide walks through every component of a JWT so you can read, debug, and reason about them with full confidence.
What Is a JWT?
A JSON Web Token (RFC 7519) is a compact, URL-safe string that encodes a set of claims — assertions about a subject (typically a logged-in user). It has three Base64URL-encoded parts separated by dots:
The three parts are: header · payload · signature. The Dev Cosmos JWT Decoder colour-codes each part exactly this way.
The Header
The header is a JSON object that specifies the token type and signing algorithm:
{
"alg": "HS256", // Signing algorithm
"typ": "JWT" // Token type
}
Common algorithms:
| Algorithm | Type | Use Case |
|---|---|---|
HS256 | Symmetric (HMAC) | Single-server — same key signs and verifies |
RS256 | Asymmetric (RSA) | Multi-service — private key signs, public key verifies |
ES256 | Asymmetric (ECDSA) | Same as RS256 but shorter keys, faster |
none | No signature | Development only — never in production |
"alg": "none" and skipped signature verification entirely. An attacker could forge any token. Always verify the algorithm in your server-side code and reject none.The Payload
The payload contains claims — key-value pairs about the token subject. There are three types:
Registered Claims (Standard)
| Claim | Full Name | Description |
|---|---|---|
iss | Issuer | Who created and signed the token (e.g. "auth.myapp.com") |
sub | Subject | Who the token refers to (usually a user ID) |
aud | Audience | Who the token is intended for (e.g. "api.myapp.com") |
exp | Expiration | Unix timestamp after which the token is invalid |
nbf | Not Before | Unix timestamp before which the token is not valid |
iat | Issued At | Unix timestamp when the token was created |
jti | JWT ID | Unique identifier — used to prevent replay attacks |
Private Claims (Custom)
Your application can add any custom claims:
{
"sub": "user_1234",
"email": "alice@example.com",
"role": "admin",
"permissions": ["read:orders", "write:products"],
"iat": 1705318200,
"exp": 1768476800
}
The Signature
The signature is a cryptographic MAC (Message Authentication Code) over the header and payload. It's computed as:
HMACSHA256(
base64url(header) + "." + base64url(payload),
secret
)
The server verifies the signature on every request to confirm the token hasn't been tampered with. If anyone changes even one character of the payload, the signature becomes invalid.
Expiry and the Progress Bar
The decoder shows a visual progress bar between iat (issued at) and exp (expiry). The bar turns amber when more than 70% of the token's lifetime has elapsed, and red when over 90%. This gives you an instant visual of how long the token has left.
When debugging authentication failures, expiry is the first thing to check. A 401 from your API almost always means an expired token on the client side.
JWT Security Best Practices
- Short expiry times — 15 minutes for access tokens, 7–30 days for refresh tokens. Shorter tokens limit the damage window if a token is stolen.
- Use RS256 in distributed systems — with asymmetric signing, downstream services only need the public key to verify tokens, not your private signing secret.
- Store tokens securely — use
httpOnlycookies to prevent XSS access. AvoidlocalStoragefor sensitive tokens. - Implement token revocation — stateless JWTs can't be invalidated before expiry without a revocation list (blocklist). Design your auth flow accordingly.
- Validate all claims — check
iss,aud, andexpon every request. Don't trust a valid signature alone.
Debugging Workflow
- Copy the token from your browser's DevTools (Network tab → request headers →
Authorization: Bearer ...) - Paste into the Dev Cosmos JWT Decoder
- Check the expiry progress bar — is it expired?
- Inspect the payload claims — correct user ID? correct role?
- Verify the algorithm in the header matches what your server expects