← Back to Blog

JWT Tokens Explained: Header, Payload, Signature and Security

JSON Web Tokens appear in nearly every modern API and authentication flow. This guide breaks down exactly how they work, how to verify them, and where things go wrong.

Pankaj Kumar
Senior Software Engineer — .NET, Blazor, ASP.NET Core
4+ years building production .NET and Blazor applications. Every DevToolsHub tool and article comes from real daily development work — not documentation summaries.
Published 20 May 2026· Last reviewed Jul 2026· 7 min read · About the author →
Implemented JWT authentication in ASP.NET Core, Node.js, and Go services. Has found the alg:none vulnerability in a real codebase during a security audit — the section on algorithm confusion attacks is from lived experience.
Key takeaways
  • The three-part structure of a JWT: header, payload, and signature
  • Why the payload is readable by anyone — and what that means for sensitive data
  • HS256 vs RS256: when to use symmetric versus asymmetric signing in production
  • The 5 most common JWT security vulnerabilities, including the alg:none attack
Table of Contents

What is a JWT?

A JSON Web Token (JWT, pronounced "jot") is an open standard (RFC 7519) for securely transmitting claims between two parties as a compact, URL-safe string. JWTs are most commonly used for authentication — once a user logs in, the server issues a JWT that the client sends with every subsequent request. The server verifies the token without needing to look up a session in a database.

Structure of a JWT

A JWT consists of three Base64URL-encoded parts separated by dots:

xxxxx.yyyyy.zzzzz
Header.Payload.Signature

1. Header

The header is a JSON object specifying the token type and the signing algorithm:

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

Common algorithms: HS256 (HMAC-SHA256, symmetric), RS256 (RSA-SHA256, asymmetric), ES256 (ECDSA-P256, asymmetric).

2. Payload

The payload contains claims — statements about the user or any other entity. There are three categories:

  • Registered claims — standardised, short-named fields: iss (issuer), sub (subject/user ID), aud (audience), exp (expiry as Unix timestamp), iat (issued-at), nbf (not-before), jti (JWT ID / unique identifier).
  • Public claims — agreed-upon custom claims registered in the IANA JWT Claims Registry.
  • Private claims — application-specific claims shared between issuer and consumer, e.g. role, email, tenantId.
{
  "sub": "user_12345",
  "email": "[email protected]",
  "role": "admin",
  "iat": 1704067200,
  "exp": 1704153600
}

Important: the payload is only Base64URL-encoded, not encrypted. Anyone who has the token can decode and read the claims. Never put sensitive information (passwords, credit card numbers, secrets) in a JWT payload unless you also encrypt it (JWE).

3. Signature

The signature ensures the token has not been tampered with. It is computed by taking the encoded header, a dot, the encoded payload, and signing them with the secret (for HS256) or private key (for RS256/ES256):

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

When the server receives a token, it recomputes the signature and compares it to the one in the token. If they match, the token is valid and unmodified.

How JWT authentication works

  1. User sends credentials (username + password) to the login endpoint.
  2. Server validates credentials and issues a signed JWT.
  3. Client stores the JWT (typically in memory or localStorage) and sends it in the Authorization header on every API request: Authorization: Bearer <token>.
  4. Server receives the token, verifies the signature, checks exp, and reads the claims — no database lookup needed.
  5. When the token expires, the client uses a refresh token to obtain a new JWT.

HS256 vs RS256 — which to use?

HS256 uses a single shared secret. Both the issuer and verifier must know the same secret. Simple to set up, but every service that needs to verify tokens must have the secret, which increases exposure.

RS256 uses a public/private key pair. The issuer signs with the private key; any consumer verifies with the public key. The private key never leaves the auth server, making this the right choice for microservices and third-party integrations. RS256 is the industry standard for production systems.

Common JWT security pitfalls

  • The "alg: none" attack — an attacker removes the signature and sets the algorithm to none, hoping the server accepts unsigned tokens. Always explicitly whitelist allowed algorithms on the server side.
  • Algorithm confusion — an attacker switches from RS256 to HS256 and signs with the public key (which is not secret). The server, if not checking the algorithm carefully, may accept it. Use a strict algorithm allowlist.
  • Storing JWTs in localStorage — vulnerable to XSS attacks. Consider storing access tokens in memory and refresh tokens in HttpOnly cookies.
  • Long expiry — a stolen token with a 30-day expiry is a serious risk. Keep access tokens short-lived (15 minutes) and use refresh tokens for session continuity.
  • No token revocation — JWTs are stateless, so you cannot invalidate one before it expires without a blocklist. Design your system with short-lived access tokens to limit exposure.

JWT vs session cookies

Both are valid authentication mechanisms, and the right choice depends on your architecture:

  • Use JWT for stateless APIs, microservices, mobile apps, and third-party token issuance (OAuth 2.0 / OpenID Connect).
  • Use session cookies for traditional server-rendered web apps where you control both the client and server, and you need the ability to instantly invalidate a session.
Try the free tool

JWT Decoder

Paste any JWT and instantly decode its header and payload. See claims, expiry, algorithm, and more — no login required.

Open JWT Decoder