How to Decode a JWT Token: Structure and Security

CodeKit
jwtsecurityauthentication

What is a JWT Token?

A JSON Web Token (JWT, pronounced “jot”) is an open standard (RFC 7519) for securely transmitting information between parties as a JSON object. JWTs are widely used in modern web applications for authentication and authorization. They are compact, URL-safe, and self-contained—meaning all the necessary information is stored within the token itself.

A JWT looks like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Notice the two periods (.) that separate the token into three distinct parts.

The Three Parts of a JWT

1. Header

The header typically consists of two fields: the token type and the signing algorithm.

{
  "alg": "HS256",
  "typ": "JWT"
}

This JSON is Base64URL-encoded to form the first part of the token. Common algorithms include:

  • HS256: HMAC using SHA-256 (symmetric)
  • RS256: RSA Signature with SHA-256 (asymmetric)
  • ES256: ECDSA using P-256 curve and SHA-256

2. Payload

The payload contains the claims—statements about the entity (usually the user) and additional data.

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

Registered claims include:

ClaimNameDescription
issIssuerWho issued the token
subSubjectWho the token refers to
audAudienceIntended recipient
expExpirationWhen the token expires
nbfNot BeforeWhen the token becomes valid
iatIssued AtWhen the token was issued
jtiJWT IDUnique identifier for the token

You can add any custom claims you need, but avoid putting sensitive data in the payload—it’s not encrypted.

3. Signature

The signature is used to verify that the token hasn’t been tampered with. For HS256:

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

The signature ensures integrity but does not provide confidentiality. The header and payload are merely encoded, not encrypted.

Decoding a JWT

Decoding a JWT is straightforward since the header and payload are just Base64URL-encoded JSON:

function decodeJWT(token) {
  const parts = token.split('.');
  if (parts.length !== 3) {
    throw new Error('Invalid JWT format');
  }

  const header = JSON.parse(atob(parts[0].replace(/-/g, '+').replace(/_/g, '/')));
  const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/')));

  return { header, payload };
}

// Usage
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
const decoded = decodeJWT(token);
console.log(decoded.header);  // { alg: "HS256", typ: "JWT" }
console.log(decoded.payload); // { sub: "1234567890", name: "John Doe", iat: 1516239022 }

For a quicker way, use the JWT Decoder tool on CodeKit to instantly decode and inspect any JWT token right in your browser.

Security Best Practices

Never Store Sensitive Data in the Payload

Since the payload is only Base64URL-encoded, anyone who intercepts the token can read its contents. Never store passwords, social security numbers, or other sensitive information in JWT claims.

Always Validate the Signature

Decoding a JWT without verifying its signature is dangerous. An attacker could modify the payload and re-encode it. Always verify the signature using the appropriate secret or public key:

// Using a library like jsonwebtoken in Node.js
const jwt = require('jsonwebtoken');
const decoded = jwt.verify(token, 'your-secret-key');
// Throws an error if the signature is invalid

Set Reasonable Expiration Times

Always include an exp claim and keep expiration times short. Access tokens should typically expire in 15–30 minutes. Use refresh tokens with longer lifetimes to obtain new access tokens.

Use HTTPS

Always transmit JWTs over HTTPS. Tokens sent over plain HTTP can be intercepted by anyone on the network.

Store Tokens Securely

  • Browser: Store tokens in memory or httpOnly cookies, not in localStorage (vulnerable to XSS)
  • Mobile: Use the platform’s secure storage (Keychain on iOS, EncryptedSharedPreferences on Android)

Consider the Algorithm

  • HS256 is simpler but requires sharing the secret with all parties
  • RS256 is preferred for distributed systems—the signing key is private, but the verification key is public

Common Pitfalls

  1. “None” algorithm attack: Some JWT libraries accept {"alg": "none"} which bypasses signature verification. Always validate the algorithm explicitly.
  2. Token leakage via URLs: Avoid putting tokens in URL parameters—they can be logged by proxies and servers. Use the Authorization header instead.
  3. Not revoking tokens: JWTs are stateless by design, making revocation tricky. Consider maintaining a token blacklist or using short expiration times.

Conclusion

JWTs are a powerful tool for authentication and authorization in modern web applications. Understanding their three-part structure helps you debug issues and implement them securely. Remember: decode for inspection, verify for trust.

Want to quickly inspect a JWT token? Try the JWT Decoder on CodeKit—paste your token and instantly see the decoded header and payload.