JWT

Published 2026-08-03 09:56 Updated 2026-08-03 09:56 1436 words 8 min read ... Page views

JWT (JSON Web Token) is a compact, URL-secure token format used to transfer identity and authorization information between systems. It supports signature and encryption and is often used for identity authentication, rights control, and inter-system communication. Its structure consists of three parts: header, payload and signature. It is transmitted through Base64URL encoding. The signature ensures the integrity of the data and the trustworthiness of the source. However, the content of the payload is not encrypted, posing a risk of information leakage. JWT has advantages such as cross-language and distributed verification, but it has limitations such as difficulty in revoking tokens and expiration of permissions. When using it, it is necessary to strictly verify the signature, validity period and algorithm, and combine measures such as HTTPS and secure storage to prevent security risks.

JWT

JWT Overview

JWT (JSON Web Token) is a compact, URL-safe claim transfer format that is often used to pass identity and authorization-related information between different systems.

JWT itself is a token format and is not the same as a login protocol or a single sign-on scheme. It can be used as a token carrier in authentication, authorization and single sign-on processes.

Whether JWT is confidential depends on the specific encapsulation method. The common three-stage JWT belongs to JWS. It only provides signature or message authentication code protection, and the payload content can still be read; only when JWE is used will the payload be encrypted.

Common application scenarios of JWT

  1. Identity authentication

    After the user successfully logs in, the server issues the JWT. The client carries the token in subsequent requests, and the server determines whether the token is trustworthy by verifying the signature, validity period, issuer and audience.

  2. Access authorization

    JWT can carry declarations such as user identity, roles, permissions, or scopes. After the server completes token verification, it then determines whether the current user can access the target resource based on these statements.

  3. Information exchange between systems

    Senders can sign JWT, allowing recipients to verify that the data has been tampered with and that the token was generated by a trusted issuer. If the business also requires content to be confidential, JWE or other encrypted channels should be used.

  4. Single sign-on

    In the unified identity authentication system, the certification center can issue JWTs, and each business system verifies the token according to the agreement. JWT is just one component of a single sign-on solution, and a complete solution also needs to deal with token issuance, refreshments, revocation, and trust relationships.

Characteristics of JWT

advantages

  • Compact format: Suitable for transmission in HTTP request headers.
  • Cross-language: JWT is a standardized format, and each major language has corresponding implementation.
  • Convenient distributed verification: Resource servers can verify signatures locally, reducing reliance on centralized session storage.
  • Support declaration extension: In addition to standard declarations, you can also add business custom declarations.

limited

  • Issued tokens are not easy to revoke immediately: Mechanisms such as shortening the validity period, maintaining a blacklist, or using token version numbers are often required.
  • Payloads may leak information: JWS payload is only Base64URL encoded, not encrypted.
  • Tokens may be large: When there are too many declarations, each request will increase network overhead.
  • Permissions may expire: If permissions are written directly to the long-aging token, changes in database permissions will not be immediately reflected in the old token.

Structure of JWT

The common signature JWT consists of three parts, connected using English periods:

Header.Payload.Signature
image-001
image-001

A Header is a JSON object that usually contains the following fields:

  • typ: Token type, usually JWT.
  • alg: Signature or message authentication code algorithm, such as HS256, RS256.

Example:

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

The Header is Base64URL encoded to form the first part of the token.

Payload

Payload is used to store claims. The JWT specification defines seven registration statement names, and these fields are all optional.

statementEnglish namerole
issIssuerIdentification token issuer
subSubjectIdentification token subject, usually representing the user or principal
audAudienceIdentifies the intended recipient of the token
expExpiration TimeIdentification token expiration time
nbfNot BeforeWhen identification tokens are not available
iatIssued AtIdentification token issued time
jtiJWT IDUnique number of the identification token

In addition to registration statements, you can also add business customization statements:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Do not store sensitive information such as passwords, bank card numbers, ID numbers, and keys in unencrypted JWT Payloads. Anyone who obtains the token can decode and read the Header and Payload.

Signature

Signature is used to verify that the Header and Payload have been tampered with, and to verify that the token was issued by the party holding the corresponding key.

Taking HS256 as an example, the signature calculation process can be expressed as:

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

When using HMAC, the issuer and the verifier share the same key; when using RSA or ECDSA, the issuer uses a private key to sign, and the verifier uses a public key to verify the signature.

Signature can only ensure integrity and source credibility, and cannot hide Payload content.

Base64URL

Base64URL is a Base64 variant suitable for URL and HTTP header transmission.

Compared with ordinary Base64, it mainly performs the following processing:

  • Replace + with -.
  • Replace / with _.
  • Omit the = padding characters at the end.

Base64URL is an encoding method, not an encryption algorithm.

Using JJWT encapsulation tool classes

The following example is based on JJWT 0.12.x. The keys in the configuration items are encoded using Base64 and should at least meet the key length requirements of the selected HMAC algorithm after decoding.

configuration example

jwt:
  secret: ${JWT_SECRET}
  expire-ms: 86400000

JWT_SECRET should not be submitted directly to the code warehouse, but can be injected through environment variables or key management services.

JWT tool class

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.List;

@Component
public class JwtUtil {

    private final SecretKey key;
    private final long expireMs;

    public JwtUtil(
            @Value("${jwt.secret}") String secret,
            @Value("${jwt.expire-ms}") long expireMs) {
        byte[] keyBytes = Decoders.BASE64.decode(secret);
        this.key = Keys.hmacShaKeyFor(keyBytes);
        this.expireMs = expireMs;
    }

    public String createToken(
            Long userId,
            String username,
            Long roleId,
            List<String> permissions) {
        Date now = new Date();
        Date expiration = new Date(now.getTime() + expireMs);

        return Jwts.builder()
                .subject(username)
                .claim("userId", userId)
                .claim("roleId", roleId)
                .claim("permissions", permissions)
                .issuedAt(now)
                .expiration(expiration)
                .signWith(key)
                .compact();
    }

    public Claims parseToken(String token) {
        return Jwts.parser()
                .verifyWith(key)
                .build()
                .parseSignedClaims(token)
                .getPayload();
    }

    public boolean isExpired(Claims claims) {
        Date expiration = claims.getExpiration();
        return expiration != null && expiration.before(new Date());
    }
}

signWith(key) will select a compatible signature algorithm based on the key type and length. If the system requires a fixed algorithm, it should be configured uniformly at both sides of issuance and verification, and only expected algorithms should be accepted.

Claims object

Claims represents the collection of declarations in JWT. It inherits the key-value access capabilities of Map<String, Object> and provides a dedicated method to read standard declarations.

Common methods are as follows:

String subject = claims.getSubject();
Date issuedAt = claims.getIssuedAt();
Date expiration = claims.getExpiration();
String issuer = claims.getIssuer();

When reading a custom declaration, you can specify the target type:

Long userId = claims.get("userId", Long.class);
Long roleId = claims.get("roleId", Long.class);

For generic collections, due to Java type erasure, only the original List is usually obtained when reading directly. You can convert one by one at the business level, or use a custom deserialization scheme.

@SuppressWarnings("unchecked")
List<String> permissions = claims.get("permissions", List.class);

Creation and parsing of test tokens

The following test creates and resolves tokens in the same test method, avoiding using hard-coded tokens that have expired or been corrupted by line breaks.

import io.jsonwebtoken.Claims;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

@SpringBootTest
class JwtUtilTests {

    @Autowired
    private JwtUtil jwtUtil;

    @Test
    void shouldCreateAndParseToken() {
        List<String> permissions = List.of(
                "permission:query",
                "permission:insert",
                "permission:update",
                "permission:delete",
                "permission:check"
        );

        String token = jwtUtil.createToken(130L, "tom", 3L, permissions);
        Claims claims = jwtUtil.parseToken(token);

        assertEquals("tom", claims.getSubject());
        assertEquals(130L, claims.get("userId", Long.class));
        assertEquals(3L, claims.get("roleId", Long.class));
        assertFalse(jwtUtil.isExpired(claims));

        @SuppressWarnings("unchecked")
        List<String> parsedPermissions = claims.get("permissions", List.class);
        assertEquals(permissions, parsedPermissions);
    }
}

precautions for use

  1. The server must verify the signature and cannot just decode the Payload.
  2. exp should be verified, and iss, aud, nbf and other statements should be verified according to business needs.
  3. Do not accept any algorithm specified by the client itself, and limit the allowed algorithm and token types.
  4. The HMAC key must be long enough and random to use a simple password instead of the key.
  5. Access tokens should be set with a short validity period; when long-term login is required, a refresh token mechanism should be used.
  6. Use HTTPS throughout the process to prevent tokens from being stolen during transmission.
  7. Client storage solutions should be selected based on threat models and focus on preventing XSS, CSRF and token leaks.

If you enjoyed this, leave a comment~

... Page views
© 2026 跨越星轨的客 @Hoshiumi
Powered by theme astro-koharu · Inspired by Shoka