What Is a JWT?
A JSON Web Token (JWT) is a compact, URL-safe token format for transmitting claims between two parties. It is the dominant format for bearer tokens in modern web APIs, OAuth 2.0 access tokens, and OIDC identity tokens. The IETF standardised it in RFC 7519, published in May 2015, formalising a de-facto format that had been in widespread use for several years before the RFC.
The key properties of JWTs are:
- Self-contained: The token carries the claims it asserts, without requiring a database lookup to validate the contents.
- Verifiable: The signature component lets any party with the public key verify that the token was issued by the claimed issuer and has not been tampered with.
- URL-safe: Base64url encoding ensures JWTs can be included in URLs and HTTP headers without escaping.
The Three-Part Structure
A JWT consists of three Base64url-encoded components separated by dots:
header.payload.signature- Header: A JSON object specifying the token type (
"typ": "JWT") and the signing algorithm ("alg": "HS256"). - Payload: A JSON object containing the claims — assertions about the subject. Standard registered claims include
iss(issuer),sub(subject),aud(audience),exp(expiration time), andiat(issued at). Application-specific claims can be added freely. - Signature: The result of signing
Base64url(header).Base64url(payload)with the specified algorithm and key. For HS256, this is an HMAC-SHA256 over the header and payload using a shared secret. For RS256, it is an RSA signature using a private key.
Base64url's Role
Standard Base64 uses + and / as its 62nd and 63rd characters, and = for padding. These characters are special in URLs and HTTP headers. Base64url substitutes - for + and _ for /, and typically omits the padding = character entirely.
This makes the entire JWT safe to include in a URL query parameter, an Authorization: Bearer header, or a cookie value without percent-encoding. The Base64url alphabet is defined in RFC 4648 Section 5, published the same year as the JWT RFC.
Crucially, Base64url is an encoding, not an encryption. The payload of a JWT is readable by anyone who holds the token — Base64url decoding is trivial and requires no key. Only the signature provides security; never put secrets in a JWT payload without also encrypting it (using JWE, RFC 7516). This distinction is explored in depth in Base64 Encoding Is Not Encryption.
Security Considerations
RFC 7519 is accompanied by explicit security guidance:
- Algorithm confusion: The
alg: nonevalue (unsigned JWT) must never be accepted by production verifiers. Early JWT libraries had bugs where they accepted unsigned tokens if the header declared"alg":"none". - Key confusion: Systems accepting both symmetric (HS256) and asymmetric (RS256) algorithms must verify the algorithm matches the expected key type, or an attacker can use a public key as the HMAC secret.
- Expiry enforcement: The
expclaim is not automatically enforced — your code must check it. Expired tokens must be rejected. - Audience validation: Always validate
audto prevent a token issued for one service from being used at another.
If your workflow involves pasting JWT payloads into online tools to inspect them, see Why You Shouldn't Paste Sensitive JSON Into Online Tools — JWT payloads often contain user IDs and session metadata that warrant careful handling.