Generating and Validating JWT Tokens in Java with JJWT

JWT Essentials

A JSON Web Token (JWT) is a compact, URL-safe string that carries digitally-signed claims. Because the signature guarantees integrity, any party in possession of the token can trust its contents without contacting the issuer. Typical use cases include single-sign-on flows, micro-service authentication, and stateless session management.

Stateless Authentication Flow

  1. Client submits credentials (e.g., username/password or API key).
  2. Server validates credentials and issues a signed JWT.
  3. Client stores the token (cookie, local storage, mobile secure storage).
  4. Every subsequent request includes the token—usually in the Authorization: Bearer <token> header.
  5. Server verifies the signature and expiration, then grants or denies access.

No server-side session storage is required; all necessary data lives inside the token.

Maven Dependency

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.12.3</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.12.3</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.12.3</version>
    <scope>runtime</scope>
</dependency>

Token Issuer

package security;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

public final class JwtIssuer {

    private static final String ISSUER = "demo-service";
    private static final Duration TTL = Duration.ofDays(3);
    private static final SecretKey KEY = Keys.hmacShaKeyFor(
        "my-256-bit-secret-key-must-be-32-chars-long!".getBytes()
    );

    public static String issue(Map<String, Object> claims) {
        Instant now = Instant.now();
        return Jwts.builder()
                   .header()
                       .add("typ", "JWT")
                       .add("alg", "HS256")
                   .and()
                   .issuer(ISSUER)
                   .issuedAt(Date.from(now))
                   .expiration(Date.from(now.plus(TTL)))
                   .id(UUID.randomUUID().toString())
                   .claims(claims)
                   .signWith(KEY, Jwts.SIG.HS256)
                   .compact();
    }
}

Token Validator

package security;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SecurityException;
import java.util.Map;

public final class JwtValidator {

    private static final SecretKey KEY = JwtIssuer.KEY;

    public static Map<String, Object> validate(String compact) throws JwtException {
        return Jwts.parser()
                   .verifyWith(KEY)
                   .requireIssuer("demo-service")
                   .build()
                   .parseSignedClaims(compact)
                   .getPayload();
    }
}

Quick Demo

public static void main(String[] args) {
    Map<String, Object> payload = Map.of("userId", 123456, "role", "ADMIN");
    String token = JwtIssuer.issue(payload);
    System.out.println("Token: " + token);

    Map<String, Object> verified = JwtValidator.validate(token);
    System.out.println("User ID: " + verified.get("userId"));
    System.out.println("Role: " + verified.get("role"));
}

Running the program prints a signed JWT followed by the extracted claims:

Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkZW1vLXNlcnZpY2UiLCJpYXQiOjE3MDg5NzQwMDAsImV4cCI6MTcwOTIzMzIwMCwianRpIjoiMGE5N2Y1YzQtZTU0Yi00MGEwLWIyMjQtZTI3YjY0MGE4MzI5IiwidXNlcklkIjoxMjM0NTYsInJvbGUiOiJBRE1JTiJ9.3bV9YqV7Kx8qG4X2yZ1A9mN6cF3tR5sU7vW0eH8jI4k
User ID: 123456
Role: ADMIN

Tags: JWT java Authentication jjwt stateless

Posted on Fri, 25 Sep 2026 16:37:21 +0000 by anthylon