Skip to main content

Command Palette

Search for a command to run...

JWTs Explained: What's Actually Inside a Token (And What Isn't)

Updated
7 min readView as Markdown
JWTs Explained: What's Actually Inside a Token (And What Isn't)

If you've ever worked with authentication in a web application, you've almost certainly encountered JWT (JSON Web Token). It's used by countless APIs, mobile apps, and modern authentication systems.

But despite its popularity, there's a surprising amount of confusion around what a JWT actually contains.

Many developers assume a JWT is encrypted. Others believe it's a secure place to store passwords or sensitive user information. Some even think it's impossible to modify.

None of those are true.

In this article, we'll break down exactly what's inside a JWT, what isn't, how it works behind the scenes, and the security mistakes developers should avoid.


What Is a JWT?

A JSON Web Token (JWT) is a compact, URL-safe string used to securely transmit claims between two parties.

Instead of storing session data on the server, the server issues a signed token containing information about the authenticated user. The client stores this token and sends it back with future requests.

A typical JWT looks like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJ1c2VySWQiOjEyMywicm9sZSI6ImFkbWluIiwiZXhwIjoxNzM1Njg5NjAwfQ
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Notice the two dots (.). They separate the token into three distinct parts.


The Three Parts of a JWT

Every JWT contains:

Header.Payload.Signature

Each section is Base64URL encoded.

Let's explore each one.


Part 1: Header

The header contains metadata describing the token.

Example:

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

Typical fields include:

  • alg → Signing algorithm

  • typ → Token type (JWT)

This information tells the server how the token was signed.

After Base64URL encoding, it becomes something like:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

This isn't encrypted—it is simply encoded.


Part 2: Payload

The payload contains claims.

Claims are pieces of information about the user or authentication event.

Example:

{
  "sub": "123456789",
  "name": "Alice",
  "role": "admin",
  "iat": 1735600000,
  "exp": 1735603600
}

Common JWT claims include:

Claim Meaning
sub Subject (usually user ID)
iss Issuer
aud Audience
iat Issued At
exp Expiration Time
nbf Not Before
jti Token Identifier

Applications can also include custom claims:

{
  "userId": 42,
  "plan": "premium",
  "role": "editor"
}

Again, this section is encoded, not encrypted.

Anyone who has the token can decode it in seconds.


Part 3: Signature

The signature is what gives JWTs their integrity.

The server computes something like:

HMACSHA256(
    Base64Url(header) + "." + Base64Url(payload),
    SECRET_KEY
)

The result becomes the third section of the token.

The server later recomputes this signature to verify:

  • The token wasn't modified

  • The token came from a trusted issuer

If even a single character in the payload changes, the signature becomes invalid.


Is JWT Encrypted?

This is the biggest misconception.

Standard JWTs are not encrypted.

They're only:

  • JSON

  • Base64URL encoded

  • Digitally signed

Encoding is not encryption.

For example:

eyJuYW1lIjoiQWxpY2UifQ

can easily be decoded back into:

{
  "name": "Alice"
}

This means anyone holding the token can read its contents.


What Should NEVER Be Stored Inside a JWT?

Since JWT payloads are readable, never store:

❌ Passwords

❌ API keys

❌ Database connection strings

❌ Credit card information

❌ OTPs

❌ Secret tokens

❌ Refresh token secrets

❌ Personal information you wouldn't want exposed

A JWT should contain only information that is safe to expose if someone inspects the token.


What SHOULD Be Stored?

JWTs work best when storing lightweight identity information.

Good examples include:

  • User ID

  • Username

  • User role

  • Permissions

  • Organization ID

  • Subscription tier

  • Token expiration

  • Issued time

Keep the payload as small as possible.

Large JWTs increase request size because the token is sent with every authenticated API call.


Can Someone Modify a JWT?

Yes.

Anyone can modify:

  • Header

  • Payload

Because they're just Base64URL-encoded text.

However, after modification, the signature becomes invalid.

For example:

Original payload:

{
  "role": "user"
}

Modified payload:

{
  "role": "admin"
}

The attacker can create the modified token—but cannot generate a valid signature without the server's secret key (or private key, depending on the signing algorithm).

The server immediately rejects it.


How JWT Verification Works

When a request arrives:

  1. The client sends the JWT.

  2. The server splits it into three parts.

  3. The server recomputes the signature.

  4. The signatures are compared.

  5. The expiration time is checked.

  6. The issuer and audience are validated (if configured).

  7. If everything matches, the request is authenticated.

If any check fails, access is denied.


JWT Does NOT Store Session State

Traditional authentication works like this:

Browser
    ↓
Session ID
    ↓
Server Session Store

The server remembers each logged-in user.

JWT authentication usually works differently:

Browser
    ↓
JWT
    ↓
Server verifies signature

No database lookup is required just to identify the user.

This makes JWTs ideal for:

  • REST APIs

  • Mobile applications

  • Microservices

  • Distributed systems


Common JWT Myths

Myth 1: JWT Is Encrypted

False.

It is encoded and signed.


Myth 2: JWT Cannot Be Read

False.

Anyone can decode the payload.


Myth 3: JWT Prevents Tampering Automatically

Partially true.

JWT detects tampering using the signature, but only if the server verifies it correctly.


Myth 4: Bigger JWT Means More Secure

False.

Large JWTs only increase bandwidth usage.


Myth 5: JWT Never Expires

False.

Well-designed JWTs include the exp claim and should have relatively short lifetimes.


Best Practices for Using JWTs

  • Always use HTTPS to prevent token interception.

  • Keep access tokens short-lived (for example, 15–60 minutes).

  • Store only non-sensitive claims in the payload.

  • Verify the token signature on every protected request.

  • Validate important claims such as exp, iss, and aud.

  • Use refresh tokens to obtain new access tokens instead of creating long-lived JWTs.

  • Rotate signing keys periodically where practical.

  • Never trust a decoded JWT without verifying its signature.


Decode a JWT Yourself

If you're curious about what a token contains, you can decode the first two sections manually.

The header and payload are simply Base64URL-encoded JSON. A Base64 Decoder can help you inspect those parts for learning or debugging purposes. If you're verifying token signatures or generating test data, tools like a Hash Generator can also help you understand how cryptographic hashes are used alongside signing algorithms (though a JWT signature itself is not just a plain hash).

Remember: decoding a JWT does not verify its authenticity. Only the signature verification process using the correct secret or public key can prove that a token hasn't been altered.


Final Thoughts

JWTs are one of the most widely used authentication mechanisms in modern applications, but they're often misunderstood.

The key takeaway is simple:

  • The header describes the token.

  • The payload contains readable claims.

  • The signature protects the token from tampering.

A JWT is not encrypted, not secret, and not a secure place to store sensitive information. Its real strength lies in allowing servers to verify authenticity without maintaining session state, making it an efficient and scalable choice for APIs and distributed systems.

Once you understand what each part does—and, just as importantly, what it doesn't—you'll be able to design more secure authentication systems and avoid many of the common pitfalls developers encounter when working with JWTs.