Security

What Are JSON Web Tokens (JWT)?

July 7, 202515 min readBy JSON Formatter Team

JSON Web Tokens (JWT) are a popular method for securely transmitting authentication credentials between systems. Learn how JWTs work, their structure, and security best practices.

Authentication Made Simple: JWTs provide a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed.

What Is a JWT?

A JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed.

Think of a JWT as a sealed, tamper-proof message. It's a secure message designed to be sent between two parties which can be assured it came from an expected sender. Each JWT is digitally signed using either a secret code (for symmetric algorithms like HMAC) or a private key (for asymmetric algorithms like RSA or ECDSA).

Three Key Properties

Authenticity

Proves the message really came from who it claims to be from.

Integrity

Proves the message hasn't been changed or tampered with.

Compact

Self-contained tokens that don't require database lookups.

JWT Structure: Three Parts

JWTs are made up of three parts separated by dots: header.payload.signature

1. Header

The header contains metadata information about the token. It typically includes:

  • alg: The algorithm used to sign the JWT (e.g., HS256, RS256)
  • typ: The type of token, almost always "JWT"
{
  "alg": "RS256",
  "typ": "JWT"
}

2. Payload

The payload contains the "claims" – statements about an entity and additional data. There are three types of claims:

Registered Claims

  • iss: Issuer - who issued the token
  • sub: Subject - the subject of the token (usually user ID)
  • aud: Audience - who the token is intended for
  • exp: Expiration time - when the token expires
  • iat: Issued at - when the token was issued
  • nbf: Not before - when the token becomes valid
  • jti: JWT ID - unique identifier for the token

Public and Private Claims

Public claims can be defined by anyone, while private claims are custom claims created to share specific information between parties.

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1678886400,
  "exp": 1678890000
}

⚠️ Important Note:

The payload is encoded, not encrypted. This means anyone can easily decode the JWT and read its contents. Never put sensitive information like passwords directly into the payload unless the entire JWT is encrypted (JWE).

3. Signature

The signature is created by taking the encoded header, the encoded payload, and a secret key (or private key), and running them through the cryptographic algorithm specified in the header.

Signature = Algorithm(
  Base64Url(Header) + "." + Base64Url(Payload),
  SecretKey
)

The complete JWT looks like: header.payload.signature

Symmetric Signing (HS256)

With HS256 (HMAC with SHA-256), the same secret key is used for both signing and verification. This is a symmetric cryptographic process.

How It Works

  1. The server uses the secret key to sign the JWT
  2. The client receives and stores the JWT
  3. When making requests, the client sends the JWT
  4. The server verifies the JWT using the same secret key
// Example: Signing with HS256 (Node.js)
const jwt = require('jsonwebtoken');

const payload = {
  sub: '1234567890',
  name: 'John Doe',
  admin: true
};

const token = jwt.sign(payload, 'your-secret-key', { algorithm: 'HS256' });

Asymmetric Signing (RS256)

With RS256 (RSA Signature with SHA-256), a public/private key pair is used. The private key is used to sign, and the public key is used to verify.

Advantages of RS256

  • Only the authentication server needs the private key
  • Public key can be shared with anyone who needs to verify
  • Better for distributed systems and microservices

JWTs in Authentication Flow

Here's how JWTs are typically used in a real-world authentication flow:

  1. User Logs In: User enters credentials, which are sent securely to the authentication server
  2. Server Issues JWT: If credentials are valid, the server generates a signed JWT containing user claims
  3. Client Stores JWT: The JWT is stored securely (memory, session storage, or HTTP-only cookie)
  4. API Calls: Client includes JWT in Authorization header: Bearer <token>
  5. API Verifies: Server verifies signature, checks expiration, and grants or denies access

Security Best Practices

Using JWTs securely requires careful attention to best practices:

Always Use HTTPS/TLS

JWTs are encoded, not encrypted. Always transmit over HTTPS to encrypt the communication channel.

Protect Signing Keys

Store private keys and secrets securely. If compromised, attackers can forge valid tokens.

Keep Access Tokens Short-Lived

Set expiration times to 5-15 minutes. Use refresh tokens for longer sessions.

Never Put Sensitive Data in Payload

Don't include passwords or highly sensitive PII. Anyone can decode JWT contents easily.

Validate All Claims

Always validate exp, iss, aud, and nbf claims on verification, not just the signature.

Common JWT Libraries

Popular libraries for working with JWTs include:

  • Python: PyJWT, python-jose
  • JavaScript/Node.js: jsonwebtoken, jose
  • Java: jjwt, nimbus-jose-jwt
  • C#: System.IdentityModel.Tokens.Jwt
  • Go: github.com/golang-jwt/jwt

Conclusion

JSON Web Tokens provide a powerful, standardized way to handle authentication and authorization in modern applications. Their stateless nature makes them excellent for scalable systems, while their digital signatures ensure authenticity and integrity.

Understanding how JWTs work, their structure, and security best practices is essential for building secure applications. Whether you're building a REST API, mobile app, or web application, JWTs offer a robust solution for authentication needs.

Working with JWT Payloads?

Use our free JSON formatter to decode and format JWT payloads for debugging and verification. Understand the claims embedded in your tokens.

Try JSON Formatter