My Spring OAuth2 client only grants the ROLE_USER authority to authenticated users, ignoring the authorities from resource_access
in the provided JWT.
{
"wdb": {
"roles": [
"TestRole",
"TestRoleFoo",
"TestRoleBar"
]
}
How can I setup my OAuth2 client to also grant the authorities from resource_access
(TestRole, TestRoleFoo, TestRoleBar)? Am I missing some crucial configuration here?
On my Resource Server, I'm using Springs default OAuth2 client with the following configuration:
security:
oauth2:
client:
client-id: wdb
client-secret: some-secret
access-token-uri: http://localhost:8080/auth/realms/master/protocol/openid-connect/token
user-authorization-uri: http://localhost:8080/auth/realms/master/protocol/openid-connect/auth
scope: openid profile email
authorized-grant-types: code
resource:
user-info-uri: http://localhost:8080/auth/realms/master/protocol/openid-connect/userinfo
My Keycloak Authorization Server provides me with the following JWT payload:
{
"jti": "6a666808-2b69-4de0-ab94-9ceebdac13de",
"exp": 1569674641,
"nbf": 0,
"iat": 1569674341,
"iss": "http://localhost:8080/auth/realms/master",
"aud": "account",
"sub": "f19b0443-4cce-495a-8479-ff36f82628fc",
"typ": "Bearer",
"azp": "wdb",
"auth_time": 1569674341,
"session_state": "0a411eda-0efb-4f29-99c4-b54da6298d6c",
"acr": "1",
"allowed-origins": [
"/*"
],
"realm_access": {
"roles": [
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"wdb": {
"roles": [
"TestRole",
"TestRoleFoo",
"TestRoleBar"
]
},
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid profile email",
"email_verified": true,
"user_name": "sullrich",
"name": "Sebastian Ullrich",
"preferred_username": "sullrich",
"given_name": "Sebastian",
"locale": "de",
"family_name": "Ullrich",
"email": "[email protected]"
}
Within my Resource Server, this JWT will be derived to the following OAuth2Authentication
:
{
"authorities":[
{
"authority":"ROLE_USER"
}
],
"details":{
"remoteAddress":"0:0:0:0:0:0:0:1",
"sessionId":"... session id ...",
"tokenValue":"... encoded payload ...",
"tokenType":"bearer"
},
"authenticated":true,
"userAuthentication":{
"authorities":[
{
"authority":"ROLE_USER"
}
],
"details":{
"sub":"f19b0443-4cce-495a-8479-ff36f82628fc",
"email_verified":true,
"user_name":"sullrich",
"name":"Sebastian Ullrich",
"preferred_username":"sullrich",
"given_name":"Sebastian",
"locale":"de",
"family_name":"Ullrich",
"email":"[email protected]"
},
"authenticated":true,
"principal":"Sebastian Ullrich",
"credentials":"N/A",
"name":"Sebastian Ullrich"
},
"principal":"Sebastian Ullrich",
"credentials":"",
"clientOnly":false,
"oauth2Request":{
"clientId":"wdb",
"scope":[
],
"requestParameters":{
},
"resourceIds":[
],
"authorities":[
],
"approved":true,
"refresh":false,
"responseTypes":[
],
"extensions":{
}
},
"name":"Sebastian Ullrich"
}
Sounds like you need a custom JwtAuthenticationConverter Spring will only map scopes into granted authorities by default.
You can create a class that extends the default implementation and overrides the extractAuthorities method. Then you have access to the claims and you can map them to the roles you want.
public class JwtGrantedAuthoritiesConverter extends JwtAuthenticationConverter {
@Override
protected Collection<GrantedAuthority> extractAuthorities(Jwt jwt) {
Collection<GrantedAuthority> authorities = super.extractAuthorities(jwt);
if(jwt.containsClaim("roles") && jwt.getClaimAsStringList("roles").contains("TestRole")) {
authorities.add(new SimpleGrantedAuthority("ROLE_TestRole"));
} else {
.........
}
return authorities;
}
Then you plug in your version into the resource server in your WebSecurityConfigurationAdapter:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.
......
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter(new JwtGrantedAuthoritiesConverter());
Your roles are a bit more nested i.e. under resource_access . wdb You can always create a keycloak mapper to add them under roles in the parent node to simplify things.
Here is an example of a resource server that does something similar https://github.com/wlesniak/effective-oauth2-with-spring-security-and-spring-boot/tree/master/module_8/mod8_support-service
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