Enterprise Java

Spring Security + OAuth2 Resource Server: How to Validate JWTs Like a Pro

OAuth2 and JWT (JSON Web Tokens) have become the standard for securing APIs in modern microservices and web applications.
When building a resource server with Spring Security,
properly validating incoming JWTs is essential for security and performance.

In this article, we’ll deep dive into how to configure JwtDecoder, introspect tokens when needed, and enforce scopes to achieve robust authorization.


1. What is a JWT and Why Validate It?

A JWT is a signed token that contains claims about the user or client, used to authenticate and authorize API requests.
Validation ensures the token’s signature is valid, it hasn’t expired, and contains the correct claims for the requested resource.


2. Setting Up Spring Security OAuth2 Resource Server

First, add the dependency:

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

Then configure your application to enable JWT validation:

import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.web.SecurityFilterChain;

@EnableWebSecurity
public class SecurityConfig {

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(auth -> auth
        .requestMatchers("/api/admin/**").hasAuthority("SCOPE_admin")
        .anyRequest().authenticated()
      )
      .oauth2ResourceServer(oauth2 -> oauth2
        .jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
      );
    return http.build();
  }

  private JwtAuthenticationConverter jwtAuthenticationConverter() {
    JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
    // Customize converter to map scopes to authorities if needed
    return converter;
  }
}

3. Configuring JwtDecoder

Spring Security provides default JWT decoding from the issuer’s JWK set URL.
If you want to customize validation logic or load keys manually, define a JwtDecoder bean:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;

import java.security.interfaces.RSAPublicKey;

@Configuration
public class JwtDecoderConfig {

  @Bean
  public JwtDecoder jwtDecoder(RSAPublicKey publicKey) {
    return NimbusJwtDecoder.withPublicKey(publicKey).build();
  }
}

This is useful when you manage your own keys instead of relying on an authorization server’s metadata endpoint.


4. Using Introspection for Opaque Tokens

Sometimes, you get opaque tokens instead of JWTs. In that case, introspection is required to verify the token’s validity.
Spring Security supports this with OpaqueTokenIntrospector.

import org.springframework.context.annotation.Bean;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector;

@Bean
public OpaqueTokenIntrospector introspector() {
  return new NimbusOpaqueTokenIntrospector(
    "https://auth-server.com/introspect",
    "client-id",
    "client-secret"
  );
}

Use introspection if JWT validation is not an option or you want centralized token verification.


5. Enforcing Scopes and Claims

One powerful feature in Spring Security is enforcing scopes as authorities.
With the configuration above, hasAuthority("SCOPE_admin") checks that the token contains the admin scope.

You can also extract custom claims from the JWT using a customized JwtAuthenticationConverter:

import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;

import java.util.Collection;

public class CustomJwtAuthConverter extends JwtAuthenticationConverter {

  @Override
  protected Collection<GrantedAuthority> extractAuthorities(Jwt jwt) {
    JwtGrantedAuthoritiesConverter defaultConverter = new JwtGrantedAuthoritiesConverter();
    Collection<GrantedAuthority> authorities = defaultConverter.convert(jwt);
    
    // Example: Add custom claim-based authority
    if ("admin".equals(jwt.getClaimAsString("role"))) {
      authorities.add(() -> "ROLE_ADMIN");
    }
    
    return authorities;
  }
}

Then inject this converter in your security config:

oauth2
  .jwt(jwt -> jwt.jwtAuthenticationConverter(new CustomJwtAuthConverter()));

6. Developer Opinions & Best Practices

  • Prefer JWTs when possible. They are stateless, fast, and scalable since no introspection calls are needed.
  • Use introspection if tokens are opaque or you want centralized control. This adds a network roundtrip but improves revocation and validation.
  • Carefully map scopes to authorities. Overly permissive roles can lead to security issues.
  • Keep token size minimal. Too many claims increase overhead and processing time.
  • Regularly rotate keys and validate signature algorithms. Avoid deprecated or weak algorithms.

7. Further Reading

Proper JWT validation is critical for secure APIs. Spring Security’s resource server support gives you a flexible and powerful way to achieve this with minimal code.

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button