How Decode JWT Token

By Letters2NumbersConverter.com  ·  May 14, 2026

How Decode JWT Token step by step: split the token string on its two dot separators, Base64URL-decode the first segment to read the header, Base64URL-decode the second segment to read the payload claims, and understand that the third segment — the signature — is verified with a secret key, not decoded. This guide explains every step in plain language, covers the critical difference between decoding and verifying, and includes a worked example you can follow along with.

What Is a JWT Token?

A JSON Web Token (JWT) is a compact, URL-safe way to represent claims between two parties. It is defined in RFC 7519 and is the de facto standard for stateless authentication and authorization in modern web APIs. When a user logs in, the server creates a JWT containing claims (assertions about the user), signs it with a secret key, and returns it to the client. The client sends the JWT back with every subsequent request — typically in the Authorization: Bearer <token> header — and the server verifies the signature to authenticate the request without needing to look up a session in a database.

A JWT looks like three Base64URL-encoded strings separated by dots:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgU21pdGgiLCJlbWFpbCI6ImphbmVAZXhhbXBsZS5jb20iLCJpYXQiOjE3MTY2NDMyMDAsImV4cCI6MTcxNjcyOTYwMCwiaXNzIjoiYXBpLmV4YW1wbGUuY29tIiwiYXVkIjoiYXBwLmV4YW1wbGUuY29tIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

The red part is the header, the green part is the payload, and the blue part is the signature. JWT uses Base64URL encoding, which is a variant of Base64 — use our Base64 Encoder and Decoder to experiment with encoding and decoding Base64URL strings manually.

The Three Parts of a JWT

1. Header

The header is a JSON object that describes the token type and the signing algorithm. A typical header looks like this:

{
  "alg": "HS256",
  "typ": "JWT"
}
  • alg — the signing algorithm: HS256 (HMAC-SHA256), RS256 (RSA-SHA256), ES256 (ECDSA), and others
  • typ — always JWT for JSON Web Tokens

2. Payload

The payload is a JSON object containing claims — statements about the user and any additional metadata. The JWT specification defines a set of registered claim names (short, standardised keys) alongside any custom claims your application needs:

{
  "sub": "1234567890",
  "name": "Jane Smith",
  "email": "jane@example.com",
  "iat": 1716643200,
  "exp": 1716729600,
  "iss": "api.example.com",
  "aud": "app.example.com"
}

3. Signature

The signature is computed by the server using the encoded header, the encoded payload, and a secret key — for example:

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

The signature is also Base64URL-encoded. It protects against tampering: if anyone modifies the header or payload, the recomputed signature will not match and the server will reject the token. JWTs are similar to SAML tokens, which also use Base64 encoding to carry assertions between identity providers and service providers.

How to Decode the Header Step by Step

The header is the first segment — the part before the first dot. Here is the exact process to decode it:

  1. Extract the header segment. Split the JWT string on "." and take index 0. For the example token above, that is:
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
  2. Convert Base64URL to standard Base64. Replace every - character with + and every _ character with /. This example header contains no URL-safe characters, so it stays the same.
  3. Add Base64 padding. Pad the string with = characters until its length is a multiple of 4. Calculate padding = (4 - length % 4) % 4 and append that many = characters. The example header is already 36 characters (a multiple of 4), so no padding is needed.
  4. Base64-decode the padded string. The result is a UTF-8 JSON string:
    {"alg":"HS256","typ":"JWT"}
  5. Parse the JSON. You now have a JavaScript/Python/Go object with the alg and typ fields.

JavaScript one-liner to decode any JWT header

const [headerB64] = token.split('.')
const header = JSON.parse(
  atob(headerB64.replace(/-/g, '+').replace(/_/g, '/'))
)
console.log(header) // { alg: 'HS256', typ: 'JWT' }

How to Decode the Payload Step by Step

The process for decoding the payload is identical to decoding the header — only the segment index changes. The payload is the second segment (index 1) after splitting on ".".

  1. Extract the payload segment — everything between the first and second dots.
  2. Replace Base64URL characters: -+, _/.
  3. Pad with = until the string length is divisible by 4.
  4. Base64-decode to get the JSON string.
  5. Parse the JSON to access individual claims such as sub, email, and exp.

Decoding the example token's payload yields:

{
  "sub":   "1234567890",
  "name":  "Jane Smith",
  "email": "jane@example.com",
  "iat":   1716643200,   // 2024-05-25 12:00:00 UTC
  "exp":   1716729600,   // 2024-05-26 12:00:00 UTC
  "iss":   "api.example.com",
  "aud":   "app.example.com"
}

Note that iat and exp are Unix timestamps (integer seconds since 1970-01-01 00:00:00 UTC). When a JWT is passed in a URL query string, URL-encoding is applied to the JWT — use our online URL Decoder and Encoder if you need to decode a percent-encoded JWT before splitting it.

The Signature — Verified, Not Decoded

The third segment is the signature. Unlike the header and payload, the signature is not decoded — it is verified. The distinction is fundamental:

  • Decoding converts Base64URL bytes into readable text. Anyone can do it with no knowledge of the secret.
  • Verifying recomputes the HMAC or RSA signature from the header and payload using the secret key, then compares it to the signature in the token. Only the party that holds the secret can do this correctly.

If you Base64URL-decode the signature bytes, you get a raw binary HMAC or RSA digest — it is not a human-readable string, and there is nothing useful to "read" in it. The signature's purpose is purely cryptographic integrity protection, not information storage.

Security Warning: Decoded ≠ Trusted

Never trust the claims in a decoded JWT without verifying the signature. Because the header and payload are only Base64URL-encoded — not encrypted or signed on the client side — an attacker can craft a token with arbitrary claims and encode it correctly. For example, they could change "role":"user" to "role":"admin" and re-encode it.

A decoded JWT tells you what the claims say.
A verified JWT tells you those claims are authentic and have not been tampered with.

Always verify the signature on the server side using a trusted JWT library before acting on any claim. Never perform JWT verification in client-side JavaScript where the secret key would be exposed.

Common JWT Payload Claims

The JWT specification (RFC 7519) defines the following registered claim names. Using these standard names ensures interoperability between different JWT libraries and frameworks.

ClaimFull NameTypeDescription
issIssuerStringIdentifies the principal that issued the JWT — typically the domain of your authentication server, e.g. "auth.example.com".
subSubjectStringIdentifies the principal that is the subject of the JWT — usually a unique user ID such as a database primary key.
audAudienceString / ArrayIdentifies the recipients the JWT is intended for. The validating server must check that it is in the audience list and reject the token if not.
expExpiration TimeNumber (Unix timestamp)The time after which the JWT must not be accepted. Expressed as seconds since Unix epoch (1970-01-01T00:00:00Z).
iatIssued AtNumber (Unix timestamp)The time at which the JWT was issued. Useful for determining the age of a token.
nbfNot BeforeNumber (Unix timestamp)The time before which the JWT must not be accepted. Allows issuing tokens that become valid in the future.

In addition to these registered claims, you can add any custom (private) claims relevant to your application — for example role, plan, org_id, or permissions. Keep the payload small; every byte is transmitted with every request.

Full Example — JWT and Its Decoded Parts

The following is a complete worked example. The token is signed with HMAC-SHA256 (HS256). The three colour-coded segments are shown first, followed by each decoded part.

Raw JWT

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgU21pdGgiLCJlbWFpbCI6ImphbmVAZXhhbXBsZS5jb20iLCJpYXQiOjE3MTY2NDMyMDAsImV4cCI6MTcxNjcyOTYwMCwiaXNzIjoiYXBpLmV4YW1wbGUuY29tIiwiYXVkIjoiYXBwLmV4YW1wbGUuY29tIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Decoded Header

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

Decoded Payload

{
  "sub":   "1234567890",
  "name":  "Jane Smith",
  "email": "jane@example.com",
  "iat":   1716643200,
  "exp":   1716729600,
  "iss":   "api.example.com",
  "aud":   "app.example.com"
}

Signature

SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

This is an HMAC-SHA256 digest, Base64URL-encoded. It cannot be decoded to reveal the secret — it can only be verified by recomputing it server-side with the secret key.

Frequently Asked Questions

How do I decode a JWT token manually?

Split the JWT on its two dots to get three Base64URL-encoded segments. Take the first segment (header) or the second segment (payload), replace every - with + and every _ with /, add = padding until the length is a multiple of 4, then Base64-decode to get the JSON string. Our Base64 Encoder and Decoder can perform that Base64-decode step for you.

Can anyone decode a JWT token?

Yes — the header and payload are only Base64URL-encoded, not encrypted. Any party holding the JWT string can decode and read the claims. This is intentional: JWTs are designed to be readable by clients and servers alike. What only the issuing server can do is verify the signature, which is what proves the claims are authentic and unmodified.

What is the difference between decoding and verifying a JWT?

Decoding reads the Base64URL-encoded header and payload as JSON — no secret required. Verifying recomputes the HMAC or RSA signature from the header and payload using the server's secret key and confirms it matches the token's signature. A decoded JWT tells you what the claims say; a verified JWT tells you those claims are authentic. In a security context, never act on decoded claims alone — always verify first.

What does the exp claim mean in a JWT?

The exp (expiration time) claim is a Unix timestamp — the number of seconds since 1 January 1970 UTC — after which the token must not be accepted. When verifying a JWT, the server checks that the current time is before exp. If the token is expired, it must be rejected even if the signature is otherwise valid.

Is Base64URL the same as Base64?

Base64URL is a URL-safe variant of standard Base64. It replaces + with - and / with _, and omits trailing = padding. This makes JWT strings safe to embed in URLs and HTTP headers without percent-encoding. Use our Base64 Encoder and Decoder to convert between standard Base64 and raw bytes.

Related Tools and Guides