Search code examples
jwk

How to use JWKs with spring?


I got the task to implement jwks on the project. On our project, we have implemented a token validation check with oauth2. We use a jks format certificate to obtain a public key. the private key is not used in our project, since we need to check the validity of the token. Our goal is to get rid of the .jks file. There are too few resources for jwks and therefore some points are not clear. If I understand correctly, then jwks mean that there is a jwks.json file in the resources with keys inside, which we select by kid from the token header. Based on the documentation, it is not clear what kind of file it is and how it is loaded for checking by kid, that is, at what moment it happens.Does anyone have a project that can be used as an example? thanks in advance

https://docs.spring.io/spring-security-oauth2-boot/docs/2.2.x-SNAPSHOT/reference/html/boot-features-security-oauth2-authorization-server.html


Solution

  • You can use spring-boot resource server implementation.

    First, what you need is to add the following dependency to your project

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

    Second, you need to add an authentication server configuration. The JSON file that you mentioned has to be located on the authentication server or you can use JWKs URL of the authentication server. You should have a configuration in your properties file like this.

    spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https:/example.com/.well-known/openid-configuration/jwks
    spring.security.oauth2.resourceserver.jwt.issuer-uri=https:/example.com
    

    Finally, you need to follow the natural spring-security API configuration. What you need is like the following.

    @Configuration
    @EnableWebSecurity
    public class SecureSecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}")
        private String jwtSetUri;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.requiresChannel().anyRequest().requiresInsecure().and().cors()
                    .and().csrf().disable()
                    .authorizeRequests()
                    .antMatchers(HttpMethod.GET, "some path1").permitAll()
                    .antMatchers(HttpMethod.POST, "some path2").permitAll()
                    .antMatchers(HttpMethod.GET, "some path3").permitAll()
                    .antMatchers("/**").hasAuthority("some scope") // if you need this scope.
                    .anyRequest()
                    .authenticated()
                    .and()
                    .oauth2ResourceServer()
                    .jwt().decoder(jwtDecoder());
        }
    
    
        @Bean
        CorsConfigurationSource corsConfigurationSource() {
            final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();
            config.addAllowedMethod("PUT");
            config.addAllowedMethod("DELETE");
            source.registerCorsConfiguration("/**", config);
            return source;
        }
    
        private JwtDecoder jwtDecoder() {
            return NimbusJwtDecoder.withJwkSetUri(jwtSetUri)
                    .jwtProcessorCustomizer(p -> p.setJWSTypeVerifier(
                            new DefaultJOSEObjectTypeVerifier<>(new JOSEObjectType("at+jwt")))).build();
        }
    }
    

    After this, each request to your APIs should be verified automatically by the Spring by using the authentication server.