Why JWT Is Both Loved and Criticized: A Deep Dive into Token Authentication

This article compares traditional cookie‑session authentication with JWT, explains JWT’s three‑part structure, shows how to generate and verify tokens in Java, and discusses security benefits, pitfalls, and practical considerations for modern web and mobile applications.

macrozheng
macrozheng
macrozheng
Why JWT Is Both Loved and Criticized: A Deep Dive into Token Authentication

Traditional Authentication Methods

Cookie‑Session authentication stores a session ID in a browser cookie after the user logs in with a username and password. Subsequent requests automatically include the cookie, allowing the server to retrieve the session and verify the user.

User submits credentials (or SMS code).

Server validates them, creates a session, stores the SessionID in a cookie, and returns it to the client.

Later requests automatically carry the cookie; the server uses it to look up the session.

Traditional Cookie-Session flow
Traditional Cookie-Session flow

Problems arise in mobile apps (no cookie storage), cross‑domain scenarios (cookies are domain‑bound), distributed services (session synchronization), and CSRF attacks.

Improved Cookie‑Session Approach

To address these issues, the session ID can be stored in local storage or a client‑side database, while the server keeps session data in a fast store such as Redis.

User logs in with credentials or SMS code.

Server validates and stores authentication data in Redis, returning a key.

Client saves the key in local storage or a local database.

Subsequent requests include the key in a header or request body.

Server retrieves the authentication data from Redis using the key.

First login flow
First login flow
Subsequent login flow
Subsequent login flow

JWT Enters the Scene

JSON Web Token (JWT) provides a stateless alternative: the token itself carries the necessary claims, so the server does not need to store session data.

JWT Structure

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

Header – specifies token type and signing algorithm (e.g., {"alg":"HS256","typ":"JWT"}).

Payload – contains claims such as user information and standard fields (iss, exp, sub, aud, nbf, iat, jti).

Signature – HMACSHA256 of base64UrlEncode(header) + "." + base64UrlEncode(payload) using a secret key.

JWT structure diagram
JWT structure diagram

Using JWT

User logs in; server validates credentials and creates a JWT.

Client stores the JWT in a cookie or local storage.

For protected requests, the client sends the JWT in an HTTP header (e.g., Authorization: Bearer <token>).

Server verifies the token by recomputing the signature with the secret key and checking claims such as expiration.

JWT request flow
JWT request flow
JWT verification flow
JWT verification flow

Security Considerations

The HMACSHA256 signature ensures that any modification of the payload invalidates the token. Using HTTPS prevents token theft via network interception. Tokens should have reasonable expiration times, and revocation requires additional server‑side logic because a JWT cannot be invalidated before its expiry.

Common JWT Libraries (Java Example)

The Java library java-jwt can be added via Maven:

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.10.3</version>
</dependency>

Generating a token:

public static String create() {
    try {
        Algorithm algorithm = Algorithm.HMAC256("secret");
        String token = JWT.create()
            .withIssuer("auth0")
            .withSubject("subject")
            .withClaim("name", "古时的风筝")
            .withClaim("introduce", "英俊潇洒")
            .sign(algorithm);
        System.out.println(token);
        return token;
    } catch (JWTCreationException exception) {
        throw exception;
    }
}

Verifying a token:

public static Boolean verify(String token) {
    try {
        Algorithm algorithm = Algorithm.HMAC256("secret");
        JWTVerifier verifier = JWT.require(algorithm)
            .withIssuer("auth0")
            .build();
        DecodedJWT jwt = verifier.verify(token);
        System.out.println(jwt.getPayload());
        System.out.println(jwt.getClaim("name").asString());
        System.out.println(jwt.getClaim("introduce").asString());
        return true;
    } catch (JWTVerificationException exception) {
        return false;
    }
}

Demo execution prints the token, its payload, and confirms verification succeeds. Altering the payload causes a JWTVerificationException.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javasecurityJWTToken
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.