Active Organization
Currently supported mode
Currently, there is only one supported mode for "active organization" which is based on user's attributes (ATTRIBUTE_MODE
). This means that the active organization is kept in the user's attributes, they don't need to select an organization each time they log in.
- Upon login, the last active organization will be used.
- If the user doesn't have an active organization attribute and belong to one or more organization, the first one is taken by default.
- Switching organization create a new session for the user (it return a new access token).
Important note (ATTRIBUTE_MODE
) before v24.x+
Starting of the version 24.x+, the org.ro.active is not visible and not editable by standard users.
Currently, the attribute key for active organization is not configurable and is by default org.ro.active
.
It follows this format as it can be set as read-only with --spi-user-profile-declarative-user-profile-read-only-attributes=org.ro.*
of Keycloak which is recommended.
So a standard user isn't able to modify it for any malicious purpose. If not set as read-only, some mitigation were implemented.
Authenticator
For a spec-compliant approach,
you can use the "Select Organization" authenticator based on prompt=select_account
.
For more information, see the active-organization-authenticator doc.
Endpoints
2 endpoints are available.
Switch Organization
This endpoint allow a user to switch organization.
Note that switching organization create a new session for the user.
Active organization
This endpoint allow a user to get its active organization.
Mappers
New mapper
Configure the mapper
1. Create client scope
In your realm Client scopes, add a new client-scope, set the configuration and name as you wish.
2. Use the active organization mapper
3. Configure the mapper
By default, all properties are pre-configured. You can remove what you want and the mapper will adjust the claim.
Example with all pre-configured properties:
Will produce this claim in token:
"active_organization": {
"role": [
"view-organization",
"view-members",
"view-roles"
],
"name": "My Organization",
"id": "75bc86cb-8527-43af-b598-0873fa2bfea6",
"attribute": {
"test": [
"test"
]
}
},
Example with only id property:
Will produce this claim in token:
"active_organization": {
"id": "75bc86cb-8527-43af-b598-0873fa2bfea6"
},
4. Add new client scope to public client
On your public client (used by your FE application) add the newly created client scope.
5. Token claims
Then, after authentication, you should have the active organization info into the token claims.
Standard Flow (Demo)
For this demo,
- 3 different organizations have been created.
- 1 standard user has been created (with
manage-account
role).- This user was added to Organization 1 and Organization 2.
- 1 public client has been created.
- 1
active_organization
client scope has been created with the "Active Organization" pre-configured mapper and assigned to the public client.
The standard user is used for the demo flow.
1. Get initial account state.
First, we get the current account state of the user. Here we can see there is currently no org.ro.active
attribute.
2. Get current user's available organizations.
There, we get the organizations which the user is a member.
3. Get current user's active organization.
We try to get the active organization of the user.
As you may have notified in the account state response,
the user doesn't have an active organization attribute, so we have the first one by default.
4. Switch to other organization (member).
We try to switch to the other organization which the user is a member.
As you can see, the request is successful, and we get a new access_token. If you decode this new token, you will see that it contains the new active organization data.
5. Get new account state.
Let's get the user account state.
As you can see, the org.ro.active
attribute have been populated with the requested organization.
6. Switch to other organization (not a member).
Now, let's try to switch to the Organization 3, where the user is not a member.
As you can see, the user can't perform this action.
End.
Side note, if the user tries to get the active-organization without belonging to an organization,
the 404 NOT FOUND
response will be returned.
Attack Scenario and Mitigation (before v24.x+)
Starting of the version 24.x+, the org.ro.active is not visible and not editable by standard users.
Now, let's assume the standard user is malicious and knows a little about Keycloak. They may think that they can change organization by directly writing the org.ro.active
attribute.
Case with user read only attributes
If you have defined the pattern org.ro.*
as read-only as it was recommended in the
important note, the user can't modify this attribute.
They will get a 400 BAD REQUEST
response instead.
Case with no user read only attributes
Now, if you don't have or can't define the pattern org.ro.*
as read-only, no need to panic,
some mitigation measures have been implemented.
Let's imagine the user is able to make a "successful" POST
request to modify this attribute.
As you can see, they will get a 204 NO CONTENT
response (success). Now, they check on its attributes if the action was indeed successful.
Which seems to be the case, as the new active organization id match the one defined in the update account request.
However, if they try to get the active-organization
information now:
They will get a 401 UNAUTHORIZED
response. It's because we always check that the user actually belongs
to the organization before returning the information. Also, they may try to re-authenticate to see if the token claims contains the new active organization data (so they can get access to this organization features on your platform).
But actually the active organization claims will be empty too. For the same reason as before, we always check that the user actually belongs to the organization before mapping claims into the token.