I'm trying to setup Spring Security to work with Keycloak 21 but unfortunately most of the tutorials on Internet are outdated. I configured client and realms into Keycloak but Spring security is not clear what should be. I tried the code from this link:
I added these gradle dependencies:
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client:3.1.0'
implementation 'org.springframework.boot:spring-boot-starter-security:3.1.0'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.1.0'
and this yml config:
spring:
security:
oauth2:
client:
provider:
keycloak:
issuer-uri: https://ip/realms/admin_console_realm
registration:
keycloak-login:
authorization-grant-type: authorization_code
client-name: My Keycloak instance
client-id: admin_console_client
client-secret: qwerty
provider: keycloak
scope: openid,profile,email,offline_access
resourceserver:
jwt:
issuer-uri: https://ip/realms/admin_console_realm
jwk-set-uri: https://ip/realms/admin_console_realm/protocol/openid-connect/certs
It's not clear what I need to add as a Spring security configuration here:
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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeHttpRequests()
.requestMatchers("/*").hasAuthority("ROLE_TECH_SUPPORT")
.anyRequest().authenticated()
.and()
.oauth2Login();
return httpSecurity.build();
}
}
I added the role into Keycloak client:
When I open a Rest API link into the browser I'm redirected to Keycloak's login page. After successful authentication I get:
Access to ip was deniedYou don't have authorization to view this page.
HTTP ERROR 403
Do you know how I can fix this issue?
if you are trying to expose rest APIs secured with Keycloak Server (Authentication Server) then your application is a OAuth2 resource server not a OAuth2 client server and also you can't use browser for accessing your rest APIs unless they are public. For Resource Server with rest APIs you can use the below code
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://<KEYCLOAK_SERVER_IP>/realms/<YOUR_REALM_NAME>
jwk-set-uri: http://<KEYCLOAK_SERVER_IP>/realms/<YOUR_REALM_NAME>/protocol/openid-connect/certs
curl --location 'http://<KEYCLOAK_SERVER_IP>/realms/test/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=<YOUR_USER_NAME>' \
--data-urlencode 'password=<YOUR_USER_PASSWORD>' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=<KEYCLOAK_CLIENT_ID>' \
--data-urlencode 'client_secret=<KEYCLOAK_CLIENT_SECRET>' \
--data-urlencode 'scope=openid'
...
"realm_access": {
"roles": [
"default-roles-test",
"offline_access",
"MY_REALM_ROLE",
"uma_authorization"
]
},
"resource_access": {
"test-client": {
"roles": [
"MY_CLIENT_ROLE"
]
},
...
Now, we need to tell spring security from where it has look for Roles information in the JWT token.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
// Note: Please change '/mp-api/**' to your desired rest controller path.
httpSecurity
.authorizeHttpRequests(registry -> registry
.requestMatchers("/my-api/**").hasRole("MY_REALM_ROLE")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2Configurer -> oauth2Configurer.jwt(jwtConfigurer -> jwtConfigurer.jwtAuthenticationConverter(jwt -> {
Map<String, Collection<String>> realmAccess = jwt.getClaim("realm_access");
Collection<String> roles = realmAccess.get("roles");
var grantedAuthorities = roles.stream()
.map(role -> new SimpleGrantedAuthority("ROLE_" + role))
.collect(Collectors.toList());
return new JwtAuthenticationToken(jwt, grantedAuthorities);
})))
;
return httpSecurity.build();
}
}
Make sure you have proper Role Mappings for User in Keycloak.
Now, for using your rest API you can use Postman. In Postman add Bearer Token Authorization and use the latest generated access token from keycloak server.