Securing a Spring Boot endpoint with Keycloak and Spring Security 6 involves integrating your Spring Boot application with Keycloak as the identity provider (IdP) using the spring-boot-starter-oauth2-resource-server
module.
Below are the key steps:
1. Add Dependencies
Add these to your pom.xml
for Maven:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
2. Configure application.yml
or application.properties
Assuming your Keycloak realm is myrealm
, client is spring-app
, and server is at http://localhost:8080
:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/myrealm
3. Secure Endpoints with Spring Security
In Spring Security 6, use the new Lambda-style configuration:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public").permitAll()
.requestMatchers("/api/admin").hasRole("admin") // or hasAuthority("ROLE_admin")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt()
);
return http.build();
}
}
Note: Role names from Keycloak come as ROLE_
prefixed or need mapping.
4. (Optional) Map Roles Correctly from Keycloak
By default, Keycloak roles are in the realm_access.roles
claim. You may need a J
wtAuthenticationConverter
:
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
grantedAuthoritiesConverter.setAuthoritiesClaimName("realm_access.roles");
grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
return jwtAuthenticationConverter;
}
Then plug it into the config:
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtAuthenticationConverter(jwtAuthenticationConverter())
)
);
5.Protect Endpoints
@RestController
@RequestMapping("/api")
public class TestController {
@GetMapping("/public")
public String publicEndpoint() {
return "This is public";
}
@GetMapping("/admin")
public String adminEndpoint() {
return "This is admin-only";
}
@GetMapping("/user")
public String userEndpoint() {
return "This is user-accessible";
}
}
6. Configure Keycloak
In the Keycloak Admin Console:
- Create a realm:
myrealm
- Create a client:
spring-app
(client type: public or confidential) - Add roles:
admin
,user
- Assign roles to users
- Test by getting an access token via:
curl -X POST http://localhost:8080/realms/myrealm/protocol/openid-connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=spring-app" \
-d "username=user" \
-d "password=pass" \
-d "grant_type=password"
very good. Thanks
thank you