The Keycloak Organizations feature introduce changes on how users authenticate to a realm in order to identify whether a user is authenticating in the scope of an organization or the realm.
One of the key changes introduced by the feature in terms of authentication is the introduction of an identity-fist login flow whenever you are authenticating to a realm that has the feature enabled.
In this playbook you will learn about:
-
How identity-first login works and how users are mapped to organizations
-
How the domain set to an organization changes how users authenticate to a realm
-
How the domain set to an identity provider associated with an organization changes how users authenticate to a realm
-
How the authentication flow changes when the user does not exist in a realm or not a member of any organization
-
How the authentication flow changes when the user exist in a realm and not yet a member of any organization
The Keycloak Organization feature is a experimental feature that needs to be enabled when starting (or building an optimized image of) the server:
docker run --name kc-orgs -d -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8080:8080 quay.io/keycloak/keycloak:nightly start-dev --features organization
Once you run the command above, make sure you can access the server at http://localhost:8080/
and log in into the administration console using the following credentials:
-
Username:
admin
-
Password:
admin
You can now follow the instructions in this playbook.
In this playbook you are going to use the Keycloak Admin CLI to connect to the server instance and manage the realms. For that, run the command below to authenticate and configure the CLI:
kcadm.sh config credentials --server http://localhost:8080 --realm master --user admin
Once you run the command above, type admin
when prompted for a password.
Let us start by creating a new realm called orgdemo
:
kcadm.sh create realms -f - << EOF
{
"realm": "orgdemo",
"enabled": true
}
EOF
In this playbook, the orgdemo
realm is a first-party company that wants to integrate with third-parties, the organizations
, so that their users can have access to protected resources served by client applications available at the orgdemo
realm.
You also need some users in the orgdemo
realm to authenticate and follow the next steps.
The mjane
user is a realm user that has a email that does not match any organization in the realm. We will use this user to represent an existing realm user in the orgdemo
realm that is not associated with any organization:
kcadm.sh create realms/orgdemo/users -f - << EOF
{
"username": "mjane",
"email": "[email protected]",
"firstName": "Mary",
"lastName": "Jane",
"enabled": true,
"credentials" : [
{
"type" : "password",
"value" : "password"
}
]
}
EOF
The [email protected]
user is a user that uses one of the domains set to an organization. This user is an existing realm user that has an email that matches one of the domains set to an organization but is not yet a member of the organization. This user could have been created through self-registration, or by integrating with a custom identity store, or even federated from an identity provider available from the realm.
kcadm.sh create realms/orgdemo/users -f - << EOF
{
"username": "alice",
"email": "[email protected]",
"firstName": "Alice",
"lastName": "Chains",
"enabled": true,
"credentials" : [
{
"type" : "password",
"value" : "password"
}
]
}
EOF
When a realm is created, the authentication flows are automatically updated to enable specific steps to authenticate and onboard organization members. The authentication flows updated are:
-
browser
-
first broker login
The main change to the browser
flow is that it defaults to an identity-first login so that users are identified before prompting for their credentials.
In regards to the first broker login
flow, the main change there is to automatically add the user as an organization member once they authenticate through the identity provider associated with an organization and successfuly complete flow.
The decision to whether or not an identity-firt login should happen is based on the availability of any organization in a realm.
If no organizations exist yet, the user will follow the usual steps to authenticate using both username and password, or any other step configured to the browser
flow.
Try reaching http://localhost:8080/realms/orgdemo/account
and you’ll see the usual login page. From this page, you can authenticate
as usual to the realm using the following credentials:
-
Username: mjane
-
Password: password
Once you submit the login form, you are authenticated to the realm and automatically redirected to the client application acting on behalf of the user. In this case, the account console.
Now, let us create an organization in the orgademo
realm:
kcadm.sh create realms/orgdemo/organizations -f - << EOF
{
"name": "orga",
"enabled": true,
"domains": [
{
"name": "orga.com"
}
]
}
EOF
Save the id
of the realm after executing the command above. You will need it later whenever you see a {orgid}
placeholder in the following commands.
Once the orga
organization is created, sign out from the client application and try to log in again. At this time, you should
be present to the identity-first login page.
Differently than the previous attempt, the orgdemo
realm has a organization and the authentication flow changed to first identify
the user before prompting for any credentials.
At the identity-first login page you can still authenticate as the mjane
user. However, the user will now authenticate in two steps. The first step will ask for the username or email only, and then provide the password in a second step. The same will happen if you try to authenticate using a user that does not exist yet at the orgdemo
realm.
In addition to identify the user once the username is provided, the identity-first login is also responsible to:
-
Match an email domain to an organization
-
Decide if the authentication flow should continue or not if an account already exists for the username provided
-
Decide how the user should be authenticated depending on how the domains and the identity providers are configured to an organization
-
Seamless authenticate users through an identity provider associated with an organization if the email domain matches the domain set to the identity provider
The identity-first login provides the very same capabilities when using the usual login page with both username and password fields. The users can still self-register by clicking on the Register
link or choose from any of identity/social providers available at the realm.
The organization domain plays an important role when managing an organization and their members. It helps to map users to an organization by looking at their email address so that an email that uses a domain from an organization can authenticate and register themselves within the scope of the organization.
In the next sections, you will look at the different steps and configuration when authenticating users with or without an account when their email address matches one of the domains of the an organization.
Trying to authenticate as a user that does not exist using an email domain that matches an organization
Try to log in again to http://localhost:8080/realms/orgdemo/account/
and type [email protected]
. There is no account associated with that email in the orgdemo
realm.
If a user that does not exist tries to authenticate using an email domain that matches an organization domain, the identity-first login page will be shown again and indicate that the username provided is not valid. At this point, there is no reason to ask the user for credentials in a second step.
There are several ways to register the user so that he can authenticate to the orgdemo
realm and eventually join the orga
organization.
If the realm has the self-registration setting enabled, the user can click on the Register
link at the identity-first login page and create an account at the orgdemo
realm. After that,
the administrator can send an invitation link to the user or manually add him as a member of the orga
organization. See the
[https://gist.github.com/pedroigor/7c14b1e08e180d1f954105bb09c57f84](Onboarding Organization Members using a Registration Link) playbook.
If the organization has an identity provider without a domain set and they are marked as public
, they can also click on the identity provider
link at the identity-first login page to automatically create an account and joing the orga
organization once they authenticate through the identity provider. See the [https://gist.github.com/pedroigor/5696da1f32370f32714fc61844fedec8](Onboarding Organization Members through an Identity Provider) playbook.
Similar to the above, if the organization has an identity provider set with one of the organization domains, the user will be automatically redirected to the identity provider
to authenticate and automatically create an account and joing the orga
organization once the flow is completed.
Try to log in again to http://localhost:8080/realms/orgdemo/account/
and type [email protected]
.
Differently than before, the user is now presented with the second step to provide the credentials. Given that the user exists in the orgdemo
realm, it should be possible to authenticate even though the user is not yet a member of the organization.
As an administrator, you can later choose to invite the user to join an organization or manually add it to an organization.
Authenticating as an existing user using an email domain that matches the domain set to an identity provider associated with an organization
The feature allows you to set a domain to an identity provider associated with an organization. This is useful when you want to make sure that users using a specific email domain always authenticate through the identity provider.
For that, run the following commands to create a new orga
realm to federate users from it using an identity provider at the orgdemo
realm, where the identity provider is linked to the orga
organization:
kcadm.sh create realms -f - << EOF
{
"realm": "orga",
"enabled": true
}
EOF
kcadm.sh create realms/orga/clients -f - << EOF
{
"protocol" : "openid-connect",
"enabled" : true,
"clientId" : "orgdemo-broker",
"clientAuthenticatorType" : "client-secret",
"secret" : "secret",
"redirectUris" : [ "*" ],
"standardFlowEnabled" : true,
"directAccessGrantsEnabled" : true,
"attributes" : {
"backchannel.logout.session.required" : "true"
}
}
EOF
kcadm.sh create realms/orga/users -f - << EOF
{
"username": "jdoe",
"email": "[email protected]",
"firstName": "John",
"lastName": "Doe",
"enabled": true,
"credentials" : [
{
"type" : "password",
"value" : "password"
}
]
}
EOF
kcadm.sh create realms/orgdemo/identity-provider/instances -f - << EOF
{
"alias" : "orga",
"displayName" : "OrgA Inc.",
"providerId" : "oidc",
"enabled" : true,
"config" : {
"tokenUrl" : "http://localhost:8080/realms/orga/protocol/openid-connect/token",
"jwksUrl" : "http://localhost:8080/realms/orga/protocol/openid-connect/certs",
"issuer" : "http://localhost:8080/realms/orga",
"loginHint" : "true",
"clientAuthMethod" : "client_secret_post",
"clientId" : "orgdemo-broker",
"clientSecret" : "secret",
"userInfoUrl" : "http://localhost:8080/realms/orga/protocol/openid-connect/userinfo",
"authorizationUrl" : "http://localhost:8080/realms/orga/protocol/openid-connect/auth",
"logoutUrl" : "http://localhost:8080/realms/orga/protocol/openid-connect/logout",
"sendIdTokenOnLogout" : "true",
"kc.org.domain": "orga.com"
}
}
EOF
kcadm.sh create realms/orgdemo/organizations/{orgid}/identity-providers -b orga
Try to log in again to http://localhost:8080/realms/orgdemo/account/
and type [email protected]
. The user is now automatically redirected to the orga
realm to authenticate.
When a user that does not exist yet in the realm tries to authenticate using an email domain that matches an organization domain, and that domain is also set to the identity provider associated with the organization, the user is automatically redirected to the identity provider.
By doing this, you can now authenticate at the orga
realm using the following credentials:
-
Username: [email protected]
-
Password: password
And once the user completes the authentication, it will be automatically redirected back to the orgdemo
realm to create an account and automatically join the orga
organization.
The same is true if you re-authenticate as the [email protected]
user. However, this time the user is already linked with the identity provider and will always authenticate through the identity provider.
Using organization metadata in bearer tokens to access protected resources from the clients in a realm
So far, we have been using the account console client at the orgdemo
realm to authenticate the user. As an OpenID Connect client, an access token is issued as a result of a successful authentication.
When authenticating in the context of an organization, the access token is automatically updated with specific claims about the organization the user is a member.
In order to map organization-specific claims into tokens, a client needs to request the organization
scope when sending authorization requests to the server.
As a result, the token will contain a claim as follows:
"organization": {
"orga": {}
}
The organization
claim can be used by clients (e.g.: from ID Tokens) and resource servers (e.g.: from access tokens) to authorize access to protected resources based on the organization that a user belongs to.
The organization
scope is a built-in optional client scope at the realm. As such, it is added to any client created in the realm, by default.