In today's world, we expect OAuth2 and OIDC compatibility. Sadly, there are many flavours of OAuth2/OIDC, both server and client side. Keycloak makes their interopability possible, but can be tough to configure.
On the same hand, Keycloak's greatest strength, arguably, is in its ability to transmit the claims necessary for Authorization. However, many client applications don't allow for the use of OAuth2/OIDC token claims in order to authorize, they allow for any Authenticated user to login to the application.
In such cases, our options are limited as to how we can Authorize only certain users:
- we can use a proxy tool, such as oauth2-proxy, but this requires the user login to be disabled or some form of "JWT" only configuration to be acceptable (Semaphore-UI is a case where this wouldn't be enough)
- we can restrict the user-base, in Keycloak this translates to limiting the users in the realm
- we can use can use custom Authentication Flows, which use conditional steps to check for roles
In this post, we will walk through creating as custom browser authentication flow.
See also the section: creating flows.
Prerequisites
For this post I've used:
- a keycloak realm with users
- an arbitray realm role "required-for-client-xyz"
Create flow
- name: browser-flow-allowing-users-in-role-xyz
- flow type: Basic flow
Now we will add 2 sub-flows
- for managing the authentication - this will be very similar to the build in "browser flow"
- for conditionally allowing/denying access based on roles
Add a sub-flow, "browser-authentication"
- name: browser-authentication
- flow type: Generic
Add another sub-flow: "check-roles-for-client-xyz"
- name check-roles-for-client-xyz
- flow type: Generic
Inside the "browser-flow-allowing-users-in-role-xyz", we need configure the 2 sub-flows.
In the "browser-authentication" we need to:
- set it to "Required"
- press "+" to "add step"
a. select "Cookie"
b. set this step to "Alternative" - press "+" to "sub-flow"
a. give name "login form" (this is fairly arbitrary)
b. set "flow type" to "Generic"
c. set this step to "Alternative"
d. on this new sub-flow step:
1. press "+" to "add step"
2. select "Username Password Form"
3. it should already be "Required"
In the "check-roles-for-client-xyz" we need to:
- set it to "Conditional"
- press "+" to "add condition"
a. select "Condition - user role"
b. set the requirement to "Required"
c. configure the Condition
1. give it an alias (arbitrary) "deny-users-not-in-role"
2. assign it the role "required-for-client-xyz"
3. switch "Negate output" to "On" and then save - press "+" to "add step"
a. select "Deny access"
b. set the requirement to "Required"
At this point we have a new Authentication flow, which handles user login and cookie authentication, as well as denies access to all users not having the role "required-for-client-xyz". This is ideal for a specific client, like an admin tool which lacks a sophisticated or configurable authorization mechanism, such as role/group claims mapping in the client.
Screenshots
Available in Google Drive