How to decode JWT tokens in a Spring Boot-based Java Application

Pravin Ghumre
5 min readAug 5, 2023

Introduction

JWT stands for JSON Web Token. It is a compact and self-contained way to securely transmit information between parties as a JSON object. JWTs are commonly used for authentication and authorization purposes in web applications and APIs.

A JWT consists of three parts separated by dots: the header, the payload, and the signature. The header specifies the algorithm used to sign the token, such as HMAC, RSA, or others. The payload contains the claims or statements about the user or entity, such as their identity or permissions. The signature is generated by combining the encoded header, encoded payload, and a secret key, using the specified algorithm. The signature is used to verify the integrity of the token and to ensure that it has not been tampered with.

JWTs are often used for stateless authentication, where the server doesn’t need to store any session information. When a user authenticates, the server generates a JWT containing relevant information (such as user ID or role) and sends it to the client. The client includes the JWT in subsequent requests, and the server can validate and extract the information from the token without needing to look up the session information. This approach simplifies the server-side implementation and allows for scalability in distributed systems.

JWTs are designed to be self-contained, which means the server can trust the information within the token without needing to query a database or perform additional checks. However, it’s important to note that JWTs should be transmitted over a secure channel (e.g., HTTPS) to prevent interception and unauthorized access to the token contents.

This blog will explain how to decode JSON Web Token (JWT) in Java using Spring Security (OAuth 2.0 Resource Server JWT).

Sample JSON Web Token (JWT)

Sample JSON Web Token (JWT)

Scenario

Let’s consider the scenario where you have to decode the JSON Web Token (JWT) and read the claims present in the payload. If the JWT token is passed as a Bearer Token (Authorization) or any custom header.

JWT Authentication Flow

Below diagram explains how JWT authentication flow working while using Spring security (OAuth 2.0 Resource Server JWT).

JWT Authentication Flow

Project Setup and Configuration

Create a Spring Boot Java application and make the below mentioned changes to decode JWT tokens using Spring Security (OAuth 2.0 Resource Server JWT).

POM.xml

Add the below mentioned maven dependencies in your application’s POM.xml

  <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.2.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>

application.yaml

As shown below, configure the authorization server and adjust algorithms, issuer-uri, and jwt-set-uri values accordingly in your application.yaml.

spring:
security:
oauth2:
resourceserver:
jwt:
algorithms: ${algorithms}
issuer-uri: ${issuer-uri}
jwk-set-uri: ${jwk-set-uri}

SecurityConfig.java

The class is required to filter the URLs to authenticate or permit as per the need of your application.

Scenario 1 — JWT passed as Bearer Token — Authorization

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuerUri;

protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

http.headers().httpStrictTransportSecurity().disable();

http
.csrf().disable()
.sessionManagement()
.and()
.authorizeRequests()
.requestMatchers("/customers/public/**").permitAll() // permit all requests to /customers/public/**
.requestMatchers("/customers/private/**").authenticated() // authenticate all requests to /customers/private/**
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt().decoder(jwtDecoder());

return http.build();

}

@Bean
public JwtDecoder jwtDecoder() {

JwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(issuerUri).build();

return new JwtDecoder() {
@Override
public Jwt decode(String token) throws JwtException {
System.out.println("token: " + token);
Jwt jwt = jwtDecoder.decode(token);
System.out.println("jwt: " + jwt);
return jwt;
}
};
}
}

As coded in the above class, this will be able to decode the JWT token using JwtDecoder when JWT token is passed as Bearer Token in Authorization.

Scenario 2 — JWT passed as Custom Header — “x-custom-header

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtException;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuerUri;

protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

http.headers().httpStrictTransportSecurity().disable();

http
.csrf().disable()
.sessionManagement()
.and()
.authorizeRequests()
.requestMatchers("/customers/public/**").permitAll() // permit all requests to /customers/public/**
.requestMatchers("/customers/private/**").authenticated() // authenticate all requests to /customers/private/**
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.bearerTokenResolver(customBearerTokenResolver()) // added for custom bearer token
.jwt().decoder(jwtDecoder());

return http.build();

}

// added this for custom bearer token
private BearerTokenResolver customBearerTokenResolver() {
return new CustomBearerTokenResolver();
}

@Bean
public JwtDecoder jwtDecoder() {

JwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(issuerUri).build();

return new JwtDecoder() {
@Override
public Jwt decode(String token) throws JwtException {
System.out.println("token: " + token);
Jwt jwt = jwtDecoder.decode(token);
System.out.println("jwt: " + jwt);
return jwt;
}
};
}
}

Below class is required in this scenario, so code and refer the same as shown in above code.

CustomBearerTokenResolver.java

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
import org.springframework.util.StringUtils;

public class CustomBearerTokenResolver implements BearerTokenResolver {

private String X_CUSTOM_HEADER = "x-custom-header";

@Override
public String resolve(HttpServletRequest request) {
String customHeader = request.getHeader(X_CUSTOM_HEADER);
System.out.println("customHeader: " + customHeader);
if (StringUtils.hasText(customHeader)) {
return customHeader;
}
return null;
}
}

Testing

Below are the testing scenarios of how to pass the JWT token as bearer token and custom header (“x-custom-header”) in authorization.

Scenario 1 — JWT token passed as Bearer Token in Authorization.

with Bearer Token

Scenario 2 — JWT token passed as Custom Header like “x-custom-header” in Authorization.

with Custom Header

Summary

With this you will be able to decode JSON Web Tokens and read the claims present in payload when token is passed as bearer token or custom header using Java and Spring Security (OAuth 2.0 Resource Server JWT).

References

https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html

--

--