Security
Implementation details for JWT authentication, role extraction, and internal path security.
Overview
The arya-banking-user-service uses Spring Security with OAuth2 Resource Server support to secure its endpoints.
JWT Authentication Converter
All incoming requests with a Bearer JWT are processed by a custom JwtAuthenticationConverter. This converter matches the Keycloak realm's role structure.
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(jwt -> {
Map<String, Object> realmAccess = jwt.getClaim("realm_access");
Collection<String> roles = (Collection<String>) realmAccess.get("roles");
return roles.stream()
.map(role -> "ROLE_" + role)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
});
return converter;
}
Role Mapping
- Keycloak Role:
INTERNAL_SERVICE→ Spring Authority:ROLE_INTERNAL_SERVICE - Keycloak Role:
USER→ Spring Authority:ROLE_USER
Security Filter Chain
The SecurityFilterChain defines which paths are protected and what authorities are required.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/**").permitAll()
.requestMatchers("/internal/**").hasAnyAuthority("ROLE_INTERNAL_SERVICE")
.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(
jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter())));
return http.build();
}
/api/** is set to permitAll() to facilitate registration. In a production environment, this should be hardened to require ROLE_USER for all profile-related endpoints.Internal Service Communication
The /internal/** paths are restricted to service-to-service calls. The Auth Service authenticates via client_credentials to obtain a JWT with the INTERNAL_SERVICE role before calling the User Service.
Automated Account Locking
The internal security details controller allows the Auth Service to signal login failures. If the loginFailedAttempts reaches 5, the User Service automatically:
- Updates the user's status to
BLOCKED. - Publishes a
user-create-eventwith the stateBLOCKED. - Synchronizes this state if necessary with Keycloak.