Why do we need Keycloak permissions/policies/scopes if we want to control access on the backend?

Viewed 175

I'm still not able to understand the purpose of keycloak permissions/scopes/policies if we still validate user per resource based on the role of the user. I use Spring Boot and all the documentations shows that role must be included in the configuration:

...
.antMatchers("/api/account").hasRole("account")
.anyRequest() 
.authenticated(); 

We have configured the above policy in the keycloak but on the backend we again check the user role. Why do we need keycloak policy configuration?

In keycloak, we can create authorization scopes. How can I use that scope to protect my api based on this scopes?

I couldn't find a way to add authorization scopes into JWT token but keycloak provides UMA endpoints to fetch scopes, but would it be correct way to implement?

1 Answers

By default, spring-security is based on user "granted authorities" (in spring world, roles are just authorities with ROLE_ prefix). Spring-boot default configuration for JWT turns scopes into authorities.
But you might use SpEL in @PreAuthorize() or @PostAuthrize() and write security rules involving more than just user authorities. See for instance this expression taken from here:

@PreAuthorize("is(#grantingUsername) or hasAuthority('USERS_ADMIN') or onBehalfOf(#grantingUsername).can('PROXIES_EDIT')")

It checks user either:

  • is "granting user": username retrieved from JWT token equals grantingUsername path variable
  • is granted with USER_ADMIN authority
  • was granted with PROXIES_EDIT permission by "granting user"

You can write about anything with security SpEL, based on security-context (Authentication instance created from access-token JWT) and annotated method parameters or returned value.

OpenID standard only defines how resource-owners identity must be presented. It contains nothing specific about permissions.

As so, each authorization-server is using its own private-claims for permissions (roles, resource-access, etc.).

By default, Keycloak exposes realm roles in realm_access.roles claim. You can also add user roles specific to a client with client roles mapper (in admin console: clients -> some-client -> mappers and then click Add Builtin button). This will put client roles in a claim like resource_access.some-client.roles. You can also write your own mappers to feed any claim with what you need (I wrote such a mapper here). But all this is very Keycloak specific.

If you already defined user roles (or whatever your security rules are based on) in Keycloak, you should find it in JWT access-tokens (open it in a tool like https://jwt.io to check). If so, all you need to do is replace Spring default JwtGrantedAuthoritiesConverter (which converts scopes to authorities) with a converter extracting authorities from Keycloak specific claims for roles.

You could also use libs I wrote for spring-boot OpenID resource-servers.

Please refer to tutorials in this repo to get started. resource-server_with_oauthentication can provide you with a resource-server with role based access control in 5 minutes (including security rules unit-tests).

If you want to do something else than role-based access control, you'll have to override more @Beans and spring-security components. You could start with this advanced tutorials or the api module of the complete application from which I took security expression above.

Related