I don’t understand why my JwtEncoder
not firing to encode the token using the correct algorithm. Instead spring generate token using HMAC512 algorithm.
Here is my config:
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class SecurityConfiguration {
private final org.learning.security.authserver.service.UserDetailsService userDetailsService;
private final OidcUserInfoMapper mapper;
public SecurityConfiguration(
org.learning.security.authserver.service.UserDetailsService userDetailsService,
OidcUserInfoMapper mapper
) {
this.userDetailsService = userDetailsService;
this.mapper = mapper;
}
@Bean
public SecurityFilterChain authorizationFilterSecurityChain(HttpSecurity http, JwtDecoder decoder) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(
oidc -> oidc.userInfoEndpoint(userInfo -> userInfo.userInfoMapper(this.mapper))
);
http.exceptionHandling((exceptions) -> exceptions.defaultAuthenticationEntryPointFor(
new LoginUrlAuthenticationEntryPoint("/login"),
new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
))
.oauth2ResourceServer((resourceServer) -> resourceServer.jwt(jwtConfigurer -> jwtConfigurer.decoder(decoder)));
return http.build();
}
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests(
(authrize) -> authrize
.requestMatchers(HttpMethod.POST, "/auth/register").permitAll()
.requestMatchers(HttpMethod.GET, "/.well-known*").permitAll()
.requestMatchers("/login").permitAll()
.requestMatchers("/oauth2/authorize").permitAll()
.requestMatchers("/oauth2/token").permitAll()
.requestMatchers("/error").permitAll()
.anyRequest().permitAll()
).formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("client-id")
.clientSecret("$2a$10$jdJGhzsiIqYFpjJiYWMl/eKDOd8vdyQis2aynmFN0dgJ53XvpzzwC")
.redirectUri("http://localhost:4200")
.clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.clientSettings(ClientSettings.builder()
.requireAuthorizationConsent(true)
.requireProofKey(true)
.build()
)
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().build();
}
@Autowired
public void configureUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(this.userDetailsService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@EnableWebSecurity
@Configuration
public class JwtConfiguration {
@Bean
public KeyPair keyPair() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
ClassPathResource ksFile = new ClassPathResource("learning-jwt.jks");
KeyStoreFactoryBean ksFactory = new KeyStoreFactoryBean();
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(ksFile.getInputStream(), "lEarning$@SUpOIiejrguN_94153".toCharArray());
Certificate certificate = keyStore.getCertificate("learning-oauth-jwt");
PrivateKey privateKey = (PrivateKey) keyStore.getKey("learning-oauth-jwt", "lEarning$@SUpOIiejrguN_94153".toCharArray());
return new KeyPair(certificate.getPublicKey(), privateKey);
}
@Bean
public JWKSet jwkPublicSet() throws UnrecoverableKeyException, CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
RSAKey rsaKey = new RSAKey.Builder((RSAPublicKey) keyPair().getPublic())
.keyID("learning-oauth-jwt")
.algorithm(JWSAlgorithm.HS512)
.keyUse(KeyUse.SIGNATURE)
.build();
return new JWKSet(rsaKey);
}
@Bean
public JwtEncoder jwtEncoder(KeyPair keyPair) {
RSAKey rsaKey = new RSAKey.Builder((RSAPublicKey) keyPair.getPublic())
.privateKey(keyPair.getPrivate())
.keyID("learning-oauth-jwt")
.algorithm(JWSAlgorithm.HS512)
.build();
JWKSource<SecurityContext> jwkSource = new ImmutableJWKSet<>(new JWKSet(rsaKey));
return new NimbusJwtEncoder(jwkSource);
}
@Bean
public JwtDecoder jwtDecoder(KeyPair keyPair) {
JwtDecoder decoder = NimbusJwtDecoder.withPublicKey((RSAPublicKey) keyPair.getPublic()).build();
return new JwtDecoder() {
@Override
public Jwt decode(String token) throws JwtException {
System.out.println("XXX: " + token);
return decoder.decode(token);
}
};
}
}
Cors Configuration that i’m using:
@Configuration
public class CorsConfiguration implements WebMvcConfigurer {
@Override
@Order(1)
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:4200")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
}
}
Currently got this error while the JwtDecoder is called to decode the token when i want to exchange code and code_verifier for an access_token.
Authenticating request with JwtAuthenticationProvider (1/18)
XXX: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjbTRAZ21haWwuY29tIiwidXNlcm5hbWUiOiJjbTRAZ21haWwuY29tIiwiaWQiOjEsImV4cCI6MTcyMzg5NTM4N30.A4W8_j0O4Nfey6X7I2by7hOuLCWodEEp71KxrjTkmwp4GNAdQpBR1Z5RIPmwOycGUgzhS64fKXvMjhNGAkOaGA
2024-09-22T22:54:33.394+01:00 DEBUG 368846 --- [authserver] [io-9000-exec-10] o.s.s.o.s.r.a.JwtAuthenticationProvider : Failed to authenticate since the JWT was invalid
2024-09-22T22:54:33.396+01:00 TRACE 368846 --- [authserver] [io-9000-exec-10] .s.r.w.a.BearerTokenAuthenticationFilter : Failed to process authentication request
org.springframework.security.oauth2.server.resource.InvalidBearerTokenException: An error occurred while attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, or no matching key(s) found
I’m expecting my token be encoded using the JwtEncoder
I provided like its using the JwtDecoder
to decode. seems to me like authorization server is using default encoding.
Another thing is that I’m always getting same access token even if change Key Pair for RSA.