DEV Community

Cover image for Understanding JWT Authentication in Java with Encryption and Decryption
Sanjay Ghosh
Sanjay Ghosh

Posted on

Understanding JWT Authentication in Java with Encryption and Decryption

JSON Web Token (JWT) is a widely used mechanism for securely transmitting information between systems.

JWT is commonly used in:
• API authentication
• Single Sign-On (SSO)
• Microservices communication

This article explains:

  • What JWT is
  • JWT structure
  • How encryption and signing works
  • How to generate and validate JWT in Java
  • A simple diagram explaining the flow

What is JWT?

JWT (JSON Web Token) is a compact, URL-safe token format used to securely transmit information between two parties. Refer RFC7519 .

A JWT contains claims (information) that are digitally signed and optionally encrypted.

JWT tokens are typically used after a user logs in successfully. The server generates a token and sends it back to the client. The client includes this token in future requests for authentication.

JWT Structure

JWT Structure

A JWT consists of three parts separated by dots:

HEADER.PAYLOAD.SIGNATURE

Example JWT:

eyJhbGciOiJIUzI1NiJ9
.
eyJpc3MiOiJteS5jb21wYW55LmNvbSIsInN1YiI6ImpvaG4uZG9lIiwiaWF0IjoxNzczMTg0MTIwLCJleHAiOjE3NzMxODQ0MjAsImp0aSI6IjI1Y2JkNjVmLTYzODEtNGZiYi05YWMyLTk4ZTk0ZGYwYTI2YSJ9
.
UEG4iZhhtyG58V0Vcz-IHOL8MMPmDVqZdyRhoaTnYCI

Each part is Base64URL encoded. ()

1. Header

The header contains metadata about the token.

Example:

{"alg":"HS256"}

alg indicates the algorithm used to sign the token.

Common algorithms include:

  • HS256
  • RS256
  • ES256

2. Payload

The payload contains claims, which are pieces of information about the user.
Example:
{
"iss":"my.company.com",
"sub":"john.doe","iat":1773184120,
"exp":1773184420,
"jti":"25cbd65f-6381-4fbb-9ac2-98e94df0a26a"}
}

Note:
JWT payload is not encrypted by default. It is only Base64 encoded.
Anyone can decode the payload, but the signature prevents tampering.

3. Signature

The signature ensures the token has not been modified.
Example process:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
If someone modifies the payload, the signature verification will fail.

JWT Authentication Flow

Typical authentication flow:

  1. User logs in with username and password
  2. Server validates credentials
  3. Server generates a JWT
  4. Client stores the token
  5. Client sends JWT in Authorization header
  6. Server verifies the token

Example header in API request:

Authorization: Bearer

Generating JWT in java

(Example Code)

package jwt;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.UUID;
import java.nio.charset.StandardCharsets;
public class JwtTokenGenerator {
    /**
     * Generates a signed JWT token using a shared secret key.
     * @param issuer The issuer of the token.
     * @param subject The subject of the token (e.g., user ID).
     * @param secretKey The secret key for signing (must be at least 256 bits).
     * @return The compact JWT string.
     */
    public static String generateJwtToken(String issuer, String subject, String secretKey) {
        // Define the key from the secret string
        // The key should be securely managed and stored
        Key key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));

        Instant now = Instant.now();

        // Build the JWT
        String jwt = Jwts.builder()
                .setIssuer(issuer) // Set the issuer claim
                .setSubject(subject) // Set the subject claim
                .setIssuedAt(Date.from(now)) // Set the issued at time
                .setExpiration(Date.from(now.plus(5L, ChronoUnit.MINUTES))) // Set expiration for 5 minutes later
                .setId(UUID.randomUUID().toString()) // Set a unique ID for the token
                .signWith(key) // Sign the JWT with the key
                .compact(); // Compacts the JWT into its final string form

        return jwt;
    }

    public static void main(String[] args) {
        // Example usage: replace with your actual values
        String myIssuer = "my.company.com";
        String mySubject = "john.doe";
        // Key must be sufficiently long for HS256 (e.g., 32 characters or more for 256 bits)
        String mySecretKey = "aVerySecureAndLongSecretKeyForSigningJwts";

        String token = generateJwtToken(myIssuer, mySubject, mySecretKey);
        System.out.println("Generated JWT Token:");
        System.out.println(token);
    }
}

Enter fullscreen mode Exit fullscreen mode

The above code will create the token.

Validating JWT in Java
Example Code

package jwt;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.nio.charset.StandardCharsets;

public class JWTValidation {
    private static final String SECRET_KEY = "aVerySecureAndLongSecretKeyForSigningJwts";
        public static Claims validate(String token) {
                 return Jwts.parser().verifyWith(Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8))).build().parseSignedClaims(token).getPayload();
        }

    public static void main(String[] args) {
            if (args.length < 1 ) {
                    System.out.println("Please provide the token String as a parameter");
                    return;
            }
            String tokenString = args[0];
            Claims claims = validate (tokenString);
            System.out.println("Subject: " + claims.getSubject());
            System.out.println("Issuer: " + claims.getIssuer());
            System.out.println("Issued At: " + claims.getIssuedAt());
            System.out.println("Expiration: " + claims.getExpiration());
            System.out.println("ID: " + claims.getId());
            System.out.println("Audience: " + claims.getAudience());
   }


}
Enter fullscreen mode Exit fullscreen mode

By running the above code you can pass the generated token to test the validity.

Decoding JWT
Java Example

package jwt;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class JWTTokenDecoder {
    public static void decodeJWT(String token) {
        String[] parts = token.split("\\.");
        if (parts.length != 3) {
            throw new IllegalArgumentException("Invalid JWT token format");
        }

        Base64.Decoder decoder = Base64.getUrlDecoder();

        // Decode Header
        String header = new String(decoder.decode(parts[0]), StandardCharsets.UTF_8);
        System.out.println("JWT Header: " + header);

        // Decode Payload (Body)
        String payload = new String(decoder.decode(parts[1]), StandardCharsets.UTF_8);
        System.out.println("JWT Body: " + payload);

        // The signature part (parts[2]) is a hash and cannot be "decoded" into a readable string in the same way.
        // It's used for signature verification.
    }

    public static void main(String[] args) {
            if (args.length < 1 ) {
                    System.out.println("Please provide the token String as a parameter");
                    return;
            }
            String jwtToken = args[0];
            decodeJWT(jwtToken);
    }
}
Enter fullscreen mode Exit fullscreen mode

You can pass the JWT and get the decoded value

JWT Encryption vs Signing

Many developers confuse signing and encryption.
Signing ensures:
• Token integrity
• Token authenticity

Encryption ensures:
• Token confidentiality

Most JWT tokens are signed but not encrypted.

Security Best Practices

When using JWT in production:

  • Never store sensitive data in payload
  • Always use HTTPS
  • Set token expiration (exp claim) Refer: Claims , setExpiration
  • Rotate secret keys periodically
  • Validate token signature on every request

When Should You Use JWT?

JWT works well when:

  • Building stateless APIs
  • Implementing microservices authentication
  • Creating Single Sign-On systems
  • Protecting REST APIs

Source Code

All source files are available on GitHub:
Github source codes

Conclusion

JWT provides a simple and secure way to transmit claims between systems.

Understanding how JWT works internally — including header, payload, and signature — is important when implementing authentication systems in modern applications.

By using proper signing, validation, and expiration strategies, JWT can be a powerful tool for secure API authentication.

Top comments (0)