The Complete JWT Guide: Principles, Applications & Security Best Practices

JWT (JSON Web Token) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. Due to its compactness, self-containment, and cross-domain friendliness, JWT has become the mainstream solution for authentication and information exchange in modern web applications. This article starts from the basic concepts of JWT, deeply analyzes its structure, working mechanism, application scenarios, security analysis, and best practices to help developers fully master JWT technology.

I. Overview of JWT

JWT is an open standard based on JSON for transmitting claims between network application environments. It consists of three parts: Header, Payload, and Signature. The main features of JWT include:

  • Compact: JWT is small in size and can be sent via URL, POST parameter, or HTTP Header
  • Self-contained: JWT contains all the information needed about the user, avoiding multiple database queries
  • Cross-domain friendly: JWT natively supports cross-domain authentication, suitable for distributed systems and microservice architectures
  • Stateless: The server doesn't need to store session information, making horizontal scaling easy

II. JWT Structure Explained

JWT consists of three parts separated by dots (.): Header.Payload.Signature. Below is a detailed introduction to each part.

2.1 Header

The Header typically consists of two parts: the type of token (which is JWT) and the signing algorithm being used, such as HMAC SHA256 or RSA. Then, this JSON object is Base64Url encoded to form the first part of the JWT.

// JWT Header Example
{
  "alg": "HS256",
  "typ": "JWT"
}

// After Base64Url encoding:
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

2.2 Payload

The Payload part contains claims, which are statements about an entity (typically, the user) and additional data. Claims are of three types: registered claims, public claims, and private claims. Similarly, the Payload is Base64Url encoded to form the second part of the JWT.

Claim Types

Registered ClaimsThese are a set of predefined claims which are not mandatory but recommended, to provide a set of useful, interoperable claims.

Public ClaimsThese can be defined at will by those using JWTs. But to avoid collisions they should be defined in the IANA JSON Web Token Registry or be defined as a URI that contains a collision resistant namespace.

Private ClaimsThese are custom claims created to share information between parties that agree on using them and are neither registered nor public claims.

Claim Type Name Abbreviation Description
Registered Claims Issuer iss The issuer of the JWT
Subject sub The subject of the JWT (usually user ID)
Audience aud The recipient of the JWT
Expiration Time exp The expiration time of the JWT (timestamp)
Not Before nbf The JWT is not valid before this time
Issued At iat The time the JWT was issued (timestamp)
JWT ID jti Unique identifier for the JWT, used to prevent replay attacks
// JWT Payload Example
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022,
  "exp": 1516242622,
  "role": "admin"
}

// After Base64Url encoding:
// eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyNDI2MjIsInJvbGUiOiJhZG1pbiJ9

2.3 Signature

The Signature part is used to verify that the message wasn't changed along the way. For tokens signed with a private key, it also verifies the identity of the sender of the JWT. The signature is generated by: taking the encoded Header, the encoded Payload, a secret, and signing it with the algorithm specified in the Header.

Signature Formula: HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

Algorithm Type Key Security
HS256 (HMAC-SHA256) Symmetric Shared secret High (secret must be protected)
RS256 (RSA-SHA256) Asymmetric Public/private key pair High
ES256 (ECDSA-SHA256) Asymmetric (Elliptic Curve) Public/private key pair High (shorter keys)

III. How JWT Works

In authentication scenarios, the JWT workflow is as follows:

  1. User Login: User logs in with username and password (or other authentication method)
  2. Server Verification: Server verifies user credentials and generates JWT upon successful verification
  3. Return Token: Server returns the JWT to the client
  4. Store Token: Client stores the JWT locally (e.g., localStorage, sessionStorage, or Cookie)
  5. Send Request: Client includes JWT in the Authorization Header of subsequent requests
  6. Verify Token: Server verifies the JWT signature and validity to confirm user identity
  7. Return Data: After verification passes, server returns protected resources

💡 提示:Flow Diagram: User → Login Request → Server Verification → Generate JWT → Return JWT → Client Storage → Request with JWT → Server Verification → Return Resources

前端生成 JWT 示例

// Generate JWT using JavaScript (HMAC-SHA256)
const base64UrlEncode = (obj) => {
  return btoa(JSON.stringify(obj))
    .replace(/=/g, '')
    .replace(/\+/g, '-')
    .replace(/\//g, '_');
};

const generateJWT = async (payload, secret) => {
  const header = { alg: 'HS256', typ: 'JWT' };
  
  const encodedHeader = base64UrlEncode(header);
  const encodedPayload = base64UrlEncode(payload);
  
  const data = encodedHeader + '.' + encodedPayload;
  
  const encoder = new TextEncoder();
  const keyData = encoder.encode(secret);
  const messageData = encoder.encode(data);
  
  const cryptoKey = await crypto.subtle.importKey(
    'raw',
    keyData,
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign']
  );
  
  const signature = await crypto.subtle.sign('HMAC', cryptoKey, messageData);
  
  const signatureArray = Array.from(new Uint8Array(signature));
  const encodedSignature = btoa(String.fromCharCode(...signatureArray))
    .replace(/=/g, '')
    .replace(/\+/g, '-')
    .replace(/\//g, '_');
  
  return data + '.' + encodedSignature;
};

// Usage Example
const payload = {
  sub: 'user123',
  name: 'John Doe',
  role: 'admin',
  exp: Math.floor(Date.now() / 1000) + 3600
};

const token = await generateJWT(payload, 'your-secret-key');
console.log('JWT:', token);

IV. Common Application Scenarios

With its unique advantages, JWT is widely used in various scenarios:

1. Authentication

This is the most common scenario for using JWT. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. Single Sign On is a feature that widely uses JWT nowadays, because of its small overhead and its ability to be easily used across different domains.

2. Information Exchange

JWTs are a good way of securely transmitting information between parties. Because JWTs can be signed—for example, using public/private key pairs—you can be sure the senders are who they say they are. Additionally, as the signature is calculated using the header and the payload, you can also verify that the content hasn't been tampered with.

3. Single Sign-On (SSO)

Due to its cross-domain nature, JWT is ideal for implementing single sign-on systems. Users can seamlessly access other associated systems after logging in to one system without re-authentication.

4. Microservices Architecture

In a microservices architecture, each service can independently verify JWT without sharing session state, reducing system coupling and improving scalability.

5. Mobile Application Authentication

JWT is suitable for mobile application authentication because it doesn't rely on cookies and can be easily stored in the mobile device's local storage.

V. Security Analysis

Although JWT provides many conveniences, the following security issues need to be noted during use:

1. Signing Algorithm Security

Choosing a secure signing algorithm is crucial. HMAC algorithms require protecting the secret key, while RSA/ECDSA algorithms require properly safeguarding the private key. Never use the 'none' algorithm, as this allows JWTs to be arbitrarily forged.

2. Token Storage Security

The way JWT is stored directly affects security. Storing in localStorage makes it vulnerable to XSS attacks, while storing in cookies makes it vulnerable to CSRF attacks if not properly configured. It is recommended to use HttpOnly and Secure cookies to store JWTs.

3. Token Expiration Mechanism

Setting a reasonable expiration time (exp) is very important. A shorter expiration time reduces the risk of token theft. At the same time, a refresh token mechanism can be used to extend user session time while maintaining security.

4. Sensitive Information Protection

The JWT Payload is only Base64 encoded, not encrypted. Therefore, never store sensitive information such as passwords or credit card numbers in the Payload.

VI. Common Attacks and Protection

Understanding the common attacks JWT faces and their protection measures is crucial for ensuring system security:

1. XSS Attacks

Cross-Site Scripting (XSS) attacks can steal JWTs stored in localStorage. Protection measures include: escaping all user input, using Content Security Policy (CSP), and using HttpOnly cookies to store JWTs.

2. CSRF Attacks

If JWT is stored in cookies, it may be vulnerable to Cross-Site Request Forgery (CSRF) attacks. Protection measures include: using the SameSite cookie attribute, verifying the Referer/Origin Header, and using CSRF tokens.

3. Algorithm Confusion Attacks

An attacker might change the signing algorithm from RS256 to HS256 and then use the public key as the secret to forge a signature. The protection measure is to explicitly specify the expected algorithm during verification and not rely on the alg field in the JWT Header.

4. Replay Attacks

After intercepting a JWT, an attacker can replay the token to access protected resources. Protection measures include: setting a short expiration time, using one-time tokens, and recording used tokens (jti).

5. Token Theft

If a JWT is stolen during transmission, the attacker can impersonate the user. Protection measures include: always using HTTPS for transmission, setting a reasonable expiration time, and implementing a token revocation mechanism.

VII. Best Practices

Here are some best practices for using JWT:

1. Choose Secure Algorithms

Use HS256 or higher strength algorithms. For scenarios requiring asymmetric encryption, use RS256 or ES256. Never use the 'none' algorithm.

2. Set Reasonable Expiration Time

Access Token expiration time should be short (e.g., 15-30 minutes), while Refresh Token expiration time can be longer (e.g., 7 days).

3. Store Tokens Securely

Prioritize using HttpOnly + Secure + SameSite cookies to store JWTs. If you must store in localStorage, ensure your website has no XSS vulnerabilities.

4. Minimize Payload

Only store necessary information in the Payload, don't store sensitive data. The larger the JWT, the greater the overhead for each request.

5. Strictly Verify Tokens

Verify all necessary claims including signature, expiration time (exp), not before (nbf), issuer (iss), audience (aud), etc.

6. Use Refresh Token Mechanism

Use a combination of short-lived access tokens and long-lived refresh tokens to ensure both security and good user experience.

7. Implement Token Revocation Mechanism

Although JWT is stateless, in some scenarios (such as user logout, password change) tokens need to be immediately revoked. This can be implemented using a token blacklist or shortening the expiration time.

Node.js 验证 JWT 示例

// Verify JWT in Node.js
const jwt = require('jsonwebtoken');

// Auth middleware
const authMiddleware = (req, res, next) => {
  const authHeader = req.headers.authorization;
  
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'No authentication token provided' });
  }
  
  const token = authHeader.substring(7);
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET, {
      algorithms: ['HS256'],
      issuer: 'your-app',
      audience: 'your-app-audience'
    });
    
    req.user = decoded;
    next();
  } catch (error) {
    if (error.name === 'TokenExpiredError') {
      return res.status(401).json({ error: 'Token has expired' });
    }
    return res.status(401).json({ error: 'Invalid token' });
  }
};

// Generate access token and refresh token
const generateTokens = (user) => {
  const accessToken = jwt.sign(
    { userId: user.id, role: user.role },
    process.env.JWT_ACCESS_SECRET,
    { expiresIn: '15m', issuer: 'your-app' }
  );
  
  const refreshToken = jwt.sign(
    { userId: user.id },
    process.env.JWT_REFRESH_SECRET,
    { expiresIn: '7d', issuer: 'your-app' }
  );
  
  return { accessToken, refreshToken };
};

刷新令牌示例

// Refresh token example
const refreshTokenHandler = async (req, res) => {
  const { refreshToken } = req.body;
  
  if (!refreshToken) {
    return res.status(401).json({ error: 'No refresh token provided' });
  }
  
  try {
    const decoded = jwt.verify(
      refreshToken,
      process.env.JWT_REFRESH_SECRET,
      { algorithms: ['HS256'] }
    );
    
    const user = await User.findById(decoded.userId);
    if (!user) {
      return res.status(401).json({ error: 'User not found' });
    }
    
    const newAccessToken = jwt.sign(
      { userId: user.id, role: user.role },
      process.env.JWT_ACCESS_SECRET,
      { expiresIn: '15m', issuer: 'your-app' }
    );
    
    const newRefreshToken = jwt.sign(
      { userId: user.id },
      process.env.JWT_REFRESH_SECRET,
      { expiresIn: '7d', issuer: 'your-app' }
    );
    
    res.json({
      accessToken: newAccessToken,
      refreshToken: newRefreshToken
    });
  } catch (error) {
    res.status(401).json({ error: 'Invalid refresh token' });
  }
};

VIII. JWT vs Session Comparison

JWT and Session are two common authentication schemes, each with advantages and disadvantages:

Feature JWT Session
State Stateless Stateful
Storage Location Client (localStorage/Cookie) Server-side
Scalability Excellent, no session sharing needed Moderate, requires session sharing
Cross-domain Support Native support Requires additional configuration
Performance Needs signature verification each time Needs to query session storage
Mobile Apps Friendly, no cookie dependency Unfriendly, cookie-dependent
Immediate Revocation Difficult (needs blacklist) Easy, just delete session
Security Beware of XSS/CSRF attacks Beware of CSRF attacks

IX. JWT Types

According to purpose and security level, JWT can be divided into the following types:

1. JWS (JSON Web Signature)

This is the most common JWT type, using signatures to ensure message integrity and sender authentication. JWS is the preferred choice for most authentication scenarios.

2. JWE (JSON Web Encryption)

JWE provides not only signature but also encryption, protecting the confidentiality of the Payload. Suitable for scenarios where sensitive information needs to be transmitted in JWT. JWE has a more complex structure and larger size than JWS.

JWS vs JWE Comparison

Feature JWS JWE
Main Purpose Authentication, integrity verification Encrypted sensitive information transmission
Encryption No (Base64 encoding only) Yes (Content Encryption)
Size Smaller Larger
Complexity Simple Complex
Use Case Most authentication scenarios Scenarios requiring Payload confidentiality

X. TudoSi JWT Tool

To help developers use and debug JWT more conveniently, TudoSi Tools provides a professional JWT online tool that supports the following features:

  • JWT encoding and decoding
  • Support for multiple signing algorithms (HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512)
  • Real-time signature validation
  • Visual display of Header and Payload content
  • Support for custom keys and public/private keys

Try JWT Tool Now →

XI. Summary

As a modern authentication and information exchange solution, JWT has been widely used in web applications, mobile applications, and microservice architectures due to its compactness, self-containment, and cross-domain friendliness. Understanding the structure, working mechanism, and security features of JWT is the foundation for using JWT correctly.

In practical applications, developers need to choose appropriate signing algorithms, storage methods, and expiration strategies based on specific scenarios, and strictly follow security best practices to ensure system security. At the same time, using professional JWT tools can greatly improve development efficiency and debugging convenience.