Search code examples
spring-bootspring-security

Spring Security with Spring Boot 3 - Get JWT token from Security Context Holder


After migrating to spring boot 3 ,

extends ResourceServerConfigurerAdapter is deprecrated.

Hence , unable to use the overrriden method

   @Override
public void configure(ResourceServerSecurityConfigurer config) {
    config.tokenServices(tokenServices());
}

I am able to replace this with

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.csrf().disable();
    http.authorizeHttpRequests(auth->auth.
            requestMatchers(whitelistedEndPoints()).permitAll()
            .anyRequest()
            .anonymous())
            .httpBasic().disable();
    return http.build();
}

I have an existing code to get jwt token from OAuth as

 public String getJwtTokenFromAuth() {
    OAuth2Authentication auth =(OAuth2Authentication) SecurityContextHolder.getContext().getAuthentication();
  
    OAuth2AuthenticationDetails oauth2AuthenticationDetails = (OAuth2AuthenticationDetails) auth.getDetails();
    return oauth2AuthenticationDetails.getTokenValue();
}

However,

OAuth2Authentication and OAuth2AuthenticationDetails are not available

How can i replace this code/functionality with new spring security module of spring boot 3. Below is the pom dependencies , please suggest if i need to add/remove any ?

  <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

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

Solution

  • Spring Security OAuth2 is deprecated and removed for a while. The replacement is built in Spring Security itself and the dependencies to use are exactly what you already know:

    the required dependencies are:

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

    In order to gain the token value in a resource server you can do something like this

    class PrincipalIntrospector {
        
        public String token() {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            JwtAuthenticationToken oauthToken = (JwtAuthenticationToken) authentication;
            return oauthToken.getToken().getTokenValue();
        }
        
    }
    

    in order to make sure to have the role properly configured in your principal you can have something like below:

    @Bean
    public JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwt -> {
            List<String> authorities = jwt.getClaim("authorities");
            return authorities.stream().map(SimpleGrantedAuthority::new).collect(toList());
        });
    
        return jwtAuthenticationConverter;
    }
    

    in order to decode and make to spring to validate your jwt you can configure something like below:

    // used in case of public key
    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withPublicKey(this.key).build();
    }
    // used in case of the private key
    @Bean
    public JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withSecretKey(this.key).build();
    }
    

    The spring security pipeline can look like below:

    @Bean
    public SecurityFilterChain filterChain(
            JwtDecoder  decoder,
            JwtAuthenticationConverter converter,
            HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeHttpRequests(auth->auth.
                        requestMatchers(whitelistedEndPoints()).permitAll()
                        .anyRequest()
                        .authenticated())
                .oauth2ResourceServer().jwt().decoder(decoder).jwtAuthenticationConverter(converter);
        return http.build();
    }