A deep dive into Keycloak

This project contains a DIY deep dive into Keycloak.

The steps included here requires Docker (or Podman). It should also be possible to replicate the steps without Docker by adapting the steps accordingly.

Start containers

Automated via Bash, Make, and Docker-Compose

make all

Manually via Bash and Docker

Create a user defined network

To make it easy to connect Keycloak to LDAP and the mail server create a user defined network:

docker network create demo-network

Start Keycloak

We're going to use an extended Keycloak image that includes a custom theme and some custom providers.

First, build the custom providers and themes with:

mvn clean install

Then build the image with:

docker build -t demo-keycloak -f keycloak/Dockerfile .

Finally run it with:

docker run --name demo-keycloak -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin \
    -p 8080:8080 --net demo-network demo-keycloak

Start LDAP server

For the LDAP part of the demo we need an LDAP server running.

First build the image with:

docker build -t demo-ldap ldap

Then run it with:

docker run --name demo-ldap --net demo-network demo-ldap

Start mail server

In order to allow Keycloak to send emails we need to configure an SMTP server. MailHog provides an excellent email server that can used for testing.

Start the mail server with:

docker run -d -p 8025:8025 --name demo-mail --net demo-network mailhog/mailhog

Start JS Console application

The JS Console application provides a playground to play with tokens issued by Keycloak.

First build the image with:

docker build -t demo-js-console js-console

Then run it with:

docker run --name demo-js-console -p 8000:80 demo-js-console

Creating the realm

Open Keycloak Admin Console. Login with username admin and password admin.

Create a new realm called demo (find the add realm button in the drop-down in the top-left corner).

Once created set a friendly Display name for the realm, for example Demo SSO.

Create a client

Now create a client for the JS console by clicking on clients then create.

Fill in the following values:

  • Client ID: js-console
  • Click Save

On the next form fill in the following values:

  • Valid Redirect URIs: http://localhost:8000/*
  • Web Origins: http://localhost:8000

Configuring SMTP server

First lets set a email address on the admin user so we can test email delivery.

From the drop-down in the top-left corner select Master. Go to Users, click on View all users and select the admin user. Set the Email field to admin@localhost.

Now switch back to the demo realm, then click on Realm Settings then Email.

Fill in the following values:

  • Host: demo-mail Port: 1025
  • From: keycloak@localhost

Click Save and Test connection. Open your http://localhost:8025 and check that you have received an email from Keycloak.

Enable user registration

Let's enable user self-registration and at the same time require users to verify their email address.

Open the Keycloak Admin Console.

Click on Realm settings then Login.

Fill in the following values:

  • User registration: ON
  • Verify email: ON

To try this out open the JS Console.

You will be automatically redirected to the login screen. Click on Register and fill in the form. After registering you will be prompted to verify your email by clicking on a link in an email sent to your email address.

Adding claims to the tokens

What if your applications want to know something else about users? Say you want to have an avatar available for your users.

Keycloak makes it possible to add custom attributes to users as well as adding custom claims to tokens.

First open Users and select the user you registered earlier. Click on attributes and the following attribute:

  • Key: avatar_url
  • Value: https://www.keycloak.org/resources/images/keycloak_logo_480x108.png

Click Add followed by Save.

Now Keycloak knows the users avatar, but the application also needs access to this. We're going to add this through Client Scopes.

Click on Client Scopes then Create.

Fill in the following values:

  • Name: avatar
  • Consent Screen Text: Avatar

Click on Save.

Click on Mappers then Create. Fill in the following values:

  • Name: avatar
  • Mapper Type: User Attribute
  • User Attribute avatar_url
  • Token Claim Name: avatar_url
  • Claim JSON Type: String

Click Save.

Now we've created a client scope, but we also need to asign it to the client. Go to Clients and select js-console. Select Client Scopes.

We're going to add it as a Default Client Scope. So select the avatar here and click Add selected. As it's a default scope it is added to the token by default, if it's set as an optional client scope the client has to explicitly request it with the scope parameter.

Now go back to the JS Console and click Refresh.

Require consent for the application

So far we've assumed the JS Console is an internal trusted application, but what if it's a third party application? In that case we probably want the user to grant access to what the application wants to have access to.

Open the Keycloak Admin Console.

Go to Clients, select JS Console and turn on Consent Required.

Go back to the JS Console and click Login again. Now Keycloak will prompt the user to grant access to the application.

You may want to turn this off again before continuing.

Roles and groups

Keycloak has supports for both roles and groups.

Roles can be added realm-wide or to specific applications. There is also support for composite roles where a role can be a composite of other roles. This allows for instance creating a default role that can be added to all users, but in turn easily managing what roles all the users with the default role will have.

Groups have a parent/child relationship where a child inherits from its parent. Groups can be mapped to roles, have attributes or just added directly to the token for your application to resolve its meaning.

Let's start by creating a role and see it in the token.

Open the Keycloak Admin Console.

Click on Roles and Add Role. Set the Role Name to user and click Save.

Now click on Users and find the user you want to login with. Click on Role Mappings. Select user from Available roles and click Add selected.

Go back to the JS Console and click Refresh, then Access Token JSON. Notice that there is a realm_access claim in the token that now contains the user role.

Next let's create a Group. Go back to the Keycloak Admin Console.

Click on New and use mygroup as the Name. Click on Attributes and add key user_type with value consumers.

Now let's make sure this group and the claim is added to the token. Go to Client Scopes and click Create. For the name use myscope.

Click on Mappers. Click on Create.

Fill in the following values:

  • Name: groups
  • Mapper Type: Group Membership
  • Token Claim Name: groups

Click Save then go back to Mappers and click Create again.

Fill in the following values:

  • Name: type
  • Mapper Type: User Attribute
  • User Attribute: user_type
  • Token Claim Name: user_type
  • Claim JSON Type: String

Find the js-console client again and add the myscope as a default client scope.

Go back to the JS Console and click Refresh, then Access Token JSON. Notice that there is a groups claim in the token as well as a user_type claim.

Users from LDAP

Now let's try to load users from LDAP into Keycloak.

Open the admin console again. Click on User Federation, select ldap from the drop-down.

Fill in the following values:

  • Edit Mode: WRITABLE
  • Vendor: other
  • Connection URL: ldap://demo-ldap:389
  • Users DN: ou=People,dc=example,dc=org
  • Bind DN: cn=admin,dc=example,dc=org
  • Bind Credential: admin
  • Trust Email: ON

Click on Save then click on Synchronize all users.

Now go to Users and click View all users. You will see two new users bwilson and jbrown. Both these users have the password password.

Try opening the JS Console again and login with one of these users.

Users from GitHub

Now that we have users in Keycloak as well as loading users from LDAP let's get users from an external Identity Provider. For simplicity we'll use GitHub, but the same approach works for a corporate identity provider and other social networks.

Open the Keycloak Admin Console.

Click on Identity Providers. From the drop-down select GitHub. Copy the value in Redirect URI. You'll need this in a second when you create a new OAuth application in GitHub.

In a new tab open Register a new OAuth application.

Fill in the following values:

  • Application name: Keycloak
  • Homepage URL:
  • Authorization callback URL:

Now copy the value for Client ID and Client Secret from GitHub to the Keycloak Admin Console.

We also want to add a mapper to retrieve the avatar from GitHub. Click on Mappers and Create.

Fill in the following values:

  • Name: avatar
  • Mapper Type: Attribute Importer
  • Social Profile JSON Field Path: avatar_url
  • User Attribute Name: avatar_url

Try opening the JS Console again and instead of providing a username or password click on GitHub.

Notice how it automatically knows your name and also has your avatar.

Style that login

Perhaps you don't want the login screen to look like a Keycloak login screen, but rather add a splash of your own styling to it?

The Keycloak Docker image we built earlier actually contains a custom theme, so we have one ready to go.

Open the Keycloak Admin Console.

Click on Realm Settings then Themes. In the drop-down under Login Theme select sunrise.

Try opening the JS Console to login a take in the beauty of the new login screen!

You may want to change it back before you continue ;).

Keys and Signing Algorithms

By default Keycloak signs tokens with RS256, but we have support for other signing algorithms. We also have support for a single realm to have multiple keys.

It's even possible to change signing algorithms and signing keys transparently without any impact to users.

Let's first try to change the signing algorithm for the JS console client.

First let's see what algorithm is currently in use. Open the JS Console, login, then click on ID Token. This will display a rather cryptic string, which is the encoded token. Copy this value, making sure you select everything.

In a different tab open the JWT validation extension. This is a custom extension to Keycloak that allows decoding a token as well as verifying the signature of the token.

What we're interested is in the header. The field alg will show what signing algorithm is used to sign the token. It should show RS256.

Now let's change this to the new cool kid on the block, ES256.

Open the Keycloak Admin Console in a new tab. Make sure you keep the JS Console open as we want to show how it gets new tokens without having to re-login.

Click on Clients and select the js-console client. Under Fine Grained OpenID Connect Configuration switch Access Token Signature Algorithm and ID Token Signature Algorithm to ES256.

Now go back to the JS Console and click on Refresh. This will use the Refresh Token to obtain new updated ID and Access tokens.

Click on ID Token, copy it and open the JWT validation extension again. Notice that now the tokens are signed with ES256 instead of RS256.

While you're looking at the ID Token take a note of the kid, try to remember the first few characters. The kid refers to the keypair used to sign the token.

Go back to the Keycloak Admin Console. Go to Realm Settings then Keys. What we're going to do now is introduce a new set of active keys and mark the previous keys as no longer the active keys.

Click on Providers. From the drop-down select ecdsa-generated. Set the priority to 200 and click Save. As the priority is higher than the current active keys the new keys will be used next time tokens are signed.

Now go back to the JS Console and clik on Refresh. Copy the token to the JWT validation extension. Notice that the kid has now changed.

What this does is provide a seamless way of changing signatures and keys. Currently logged-in users will receive new tokens and cookies over time and after a while you can safely remove the old keys without affecting any logged-in users.

Sessions

Make sure you have the JS Console open in a tab and you're logged-in. Open the Keycloak Admin Console in another tab.

Find the user you are logged-in as and click on Sessions. Click on Logout all session.

Go back to the JS Console and click Refresh. Notice how you are now longer authenticated.

Not only can admins log out users, but users themselves can logout other sessions from the account management console.

Events

Open the Keycloak Admin Console. Click on Events and Config. Turn on Save Events and click Save.

Go back to the JS Console and click Refresh. Logout. Then when you log in use the wrong password, then login with the correct password.

Go back to the Events in the Keycloak Admin Console and notice how there are now a list of events.

Not only can Keycloak save these events to be able to display them in the admin console and account management console, but you can develop your own event listener that can do what you want with the events.

Custom stuff

Keycloak has a huge number of SPIs that allow you to develop your own custom providers. You can develop custom user stores, protocol mappers, authenticators, event listeners and a large number of other things. We have about 100 SPIs so you can customize a lot!

When we previously deployed Keycloak we also included a custom authenticator that enables users to login through email.

To enable this open the Keycloak Admin Console. Click on Authentication.

Click on Copy to create a new flow based on the browser flow. Use the name My Browser Flow.

Click on Actions and Delete for Username Password Form and OTP Form.

Click on Actions next to Browser-email forms. Then click on Add execution. Select Magic Link from the list. Once it's saved select Required for the Magic Link.

Now to use this new flow when users login select Bindings and select My Browser Flow for the Browser flow.

Open the JS Console and click Logout. For the email enter your email address and click Log In. Open your email and you should have a mail with a link which will authenticate you and bring you to the JS Console.

Now let's add WebAuthn to the mix. Open the Keycloak Admin Console. Go back to the Browser-email flow. Click Actions and Add execution. Select WebAuthn Authenticator. Then mark it as Required. You also need to register the WebAuthn required action.

Select Required Actions, Register, then select WebAuthn Register and click Ok.

Open the JS Console and click Logout. Login again. After you've done the email based login you will be prompted to configure WebAuthn. You'll need a WebAuthn security key to try this out.

Cool stuff we didn't cover!

Clustering and Caching

Keycloak leverages Infinispan to cache everything loaded from the database and user stores like LDAP. This removes the need to go to the database for every request.

Infinispan also enables us to provide a clustered mode where user sessions are distributed throughout the cluster. Enabling load balancing as well as redundancy.

Not only does Infinispan allow us to cluster within a single data center, but we also have support for multiple data centers. This works, but there are a few improvements that can be made here.

Authorization Services

Keycloak provides a way to centrally manage permissions for resources as well as support for UMA 2.0 that enables users themselves to manage permissions to their own resources.

Hopefully, soon we will have a DevNation Live session focusing only on this feature.

Dynamic Client Registration

Keycloak has a very powerful dynamic client registration service that allows users and applications themselves to register clients through a REST API. This supports clients defined in Keycloak's own client representation, standard OpenID Connect client format as well as SAML 2.0 client format.

It is also possible to define policies on what is permitted. For example you can restrict this service to specific IP ranges, automatically require consent and a lot of other policies. You can also develop your own custom policies.

OpenID Connect and SAML 2.0

Keycloak provides support for both OpenID Connect and SAML 2.0. There's even community maintained extensions for WS-Fed and CAS.

Adapters and the Keycloak Gatekeeper

If you missed the last DevNation Live session on Keycloak make sure to watch the recording. We covered how you can easily secure your applications with Keycloak.

Loads more...

For more information about Keycloak check out our homepage and our documentation.