I have micro-services running using old Spring Authorization Server and Resource Server (org.springframework.cloud:spring-cloud-starter-oauth2 deprecated now).
For new micro-service I am creating, I need to use newer version of Spring Security 5 implementation of Resource Server. (org.springframework.boot:spring-boot-starter-oauth2-resource-server)
Below is code from my authorization server.
@Configuration
public class AuthorizationServerConfig implements AuthorizationServerConfigurer {
private final PasswordEncoder passwordEncoder;
private final DataSource dataSource;
private final AuthenticationManager authenticationManager;
private final UserDetailsService userDetailsService;
private final CustomAccessTokenConverter customAccessTokenConverter;
@Value("${signing-key:123}")
private String signingKey;
public AuthorizationServerConfig(
PasswordEncoder passwordEncoder,
DataSource dataSource,
AuthenticationManager authenticationManager,
UserDetailsService userDetailsService,
CustomAccessTokenConverter customAccessTokenConverter) {
this.passwordEncoder = passwordEncoder;
this.dataSource = dataSource;
this.authenticationManager = authenticationManager;
this.userDetailsService = userDetailsService;
this.customAccessTokenConverter = customAccessTokenConverter;
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setAccessTokenConverter(customAccessTokenConverter);
jwtAccessTokenConverter.setSigningKey(signingKey);
return jwtAccessTokenConverter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public ApprovalStore approvalStore() {
return new JdbcApprovalStore(dataSource);
}
@Bean
public AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
@Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("isAuthenticated()").tokenKeyAccess("permitAll()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
endpoints.tokenStore(tokenStore());
endpoints.approvalStore(approvalStore());
endpoints.authorizationCodeServices(authorizationCodeServices());
endpoints.authenticationManager(authenticationManager);
endpoints.tokenEnhancer(tokenEnhancerChain);
endpoints.userDetailsService(userDetailsService);
}
}
How do I use the symmetric signing key to decrypt JWT in Spring Security 5?
From migration guide, https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Migration-Guide I have option to use JWT+JWK or JWT+Key but not sure what to use as my signing key is just a string.
I had faced exactly the same problem mentioned above. I have the old oaut2 Authorization Service and migrate the old Resource Service to Spring Security 5 standards.
So, it's my proposition of this problem. I chose JWT + Key scenario from OAuth2 Migration Guide.
In application.yml file I added the same singleKey and additional configuration for debugging SecurityFilterChain to be able to control authorization flow according to docs:
spring:
security:
oauth2:
resourceserver:
jwt:
key-value: zSigFffuyF5CjmLAxubSTVBt5OnfbnGPkFpvNpg2n/.....
logging:
level:
org:
springframework:
security: DEBUG
In my configuration class, I injected singleKey by @Value annotation:
@Value("${spring.security.oauth2.resourceserver.jwt.key-value}")
private String key;
then I exposed default configuration on SecurityFIlterChain:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.oauth2ResourceServer((oauth2) -> oauth2.jwt((jwt) -> jwt.decoder(jwtDecoder())));
return http.build();
}
and for customized JTWDecoder bean adding converting of my singleKey to SecretKey object:
@Bean
public JwtDecoder jwtDecoder() {
byte[] secretByte = key.getBytes();
SecretKey secretKey = new SecretKeySpec(secretByte, 0, secretByte.length, "RSA");
return NimbusJwtDecoder.withSecretKey(secretKey).build();
}
Logs withs configured debbugig:
o.s.security.web.FilterChainProxy.doFilterInternal - Securing GET /example_endpoint
o.s.s.w.c.SecurityContextPersistenceFilter.doFilter - Set SecurityContextHolder to empty SecurityContext
o.s.s.o.s.r.a.JwtAuthenticationProvider.authenticate - Authenticated token
o.s.s.o.s.r.w.BearerTokenAuthenticationFilter.doFilterInternal - Set SecurityContextHolder to JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@29cc3dff, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=172.16.57.7, SessionId=null], Granted Authorities=[SCOPE_BOU]]
o.s.security.web.FilterChainProxy.doFilter - Secured GET /example_endpoint
Like in docs: https://docs.spring.io/spring-security/reference/5.7.2/servlet/oauth2/resource-server/jwt.html#oauth2resourceserver-jwt-architecture
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With