Nowadays, there are several services to simplify user authentication like AWS Cognito, Auth0, etc. However, you can’t always depend on them. Sometimes you need something under your, or your company’s control. Whatever the reason may be, you’ll need an on-premise solution, or build one yourself. The latter is not an easy task. Anyone who has attempted it has probably come across thousands of posts and comments stating why you shouldn’t be doing it. So an on-premise solution it is, and Keycloak is an excellent alternative.

Developed by Red Hat, Keycloak is an “Open Source Identity and Access Management for Modern Applications and Services”. It is a potent tool and very easy to use. On this article, I’ll focus on how we can authenticate two React applications using the OpenID authentication protocol with Keycloak. Why React? Because it’s the framework, I prefer. Though, you could follow this tutorial with any other web development stack (Angular, Vue, Cordova, etc.)

Project structure

To accommodate all our files, we’ll use the following folder structure:

./

|_ react-app-1/

|_ react-app-2/

|_ docker-compose.yml

Each of our applications we’ll be developed in a different folder, and at the root, we’ll create the docker-compose.yml file which will setup Keycloak and a Postgres database.

Here is the body of the docker-compose.yml file:

Keycloak supports multiple different SQL databases; I just happened to prefer Postgres. We are also exposing the database port number and Keycloak’s HTTP and HTTPs ports.

Both React applications we’ll be created using create-react-app . If you don’t already have create-react-app installed, use npm install -g create-react-app to do so. Then run the following commands to create the projects.

create-react-app react-app-1

create-react-app react-app-2

We can run each application using the npm start command inside their folders.

React Apps

The following steps apply to both React applications, but for simplicity, the instructions are for a single app.

The first thing we are going to do is remove everything from the ./src folder.

Keycloak provides a JavaScript client application that we can download from the Keycloak server directly. It simplifies working with Keycloak a great deal. So, we’ll need to add it on the index.html file as a script tag.

<script src="http://127.0.0.1:8080/auth/js/keycloak.js" crossorigin="anonymous"></script>

This script provides a Keycloak constructor on the global scope. We need to create an instance of it before we can start using it. To do this, we’ll create a new module in ./src/modules/keycloak.js with the following logic.

The init function must run before we render the React application. So, let’s create the entry file of the application making sure it works this way.

The flow we want to implement with Keycloak is the following:

When the user accesses the page, we need to check if he’s already logged in. If not, then we redirect him to the login page, which Keycloak’ll handle for us. After the user enters his credentials, Keycloak will redirect it to the main app. Now, he can continue using the app.

A new Keycloak component we’ll handle this flow. So, create a new file in ./src/components/Keycloak.js .

Then we’ll create a new component called Keycloak on ./src/components/Keycloak.js where we’ll include the logic needed to interact with Keycloak .

This component will block the app from initializing until the user authenticates. So, it needs to wrap the main app component. Let’s configure the ./src/components/App.js component to see how it works.

We need to check for the window.Keycloak variable is defined in the global scope because we are going to add the Keycloak.js file directly from the Keycloak server. This way, we are guaranteed that we are working with the correct version of the library.

First Run

At this point, we are ready to run all the services and see what happens. So, on three different terminal windows run:

# Terminal 1

docker-compose up # Terminal 2

cd ./react-app-1 && PORT=3001 npm start # Terminal 3

cd ./react-app-2 && PORT=3002 npm start

On the first terminal, we launch the Postgres and Keycloak container, and on the other two, our React apps. We use the PORT environment variable to run each app on a different port (by default, it uses port 3000).

If we go to http://127.0.0.1:3001 or http://127.0.0.1:3002 , we’ll see this screen:

Don’t be discouraged. It means we are on the right track.

Keycloak’s client work as expected. It found that now user was authenticated and proceeded to redirect us to the login page. The problem is that we haven’t configured Keycloak to handle user authentication for our apps. Let’s do it now.

Configuring Keycloak

Keycloak’s documentation can be found on this link . It is very detailed and can be overwhelming at first. The point of this article is to distill part of the basic functionality to make it easier to use at first.

There are many ways to configure Keycloak:

Web interface Admin HTTP API Admin CLI

We are going to use its web interface.

Go to the admin page on https://127.0.0.1:8443/auth and fill in the credentials we configure on the docker-compose.yml file. If you left the default values on the example file, they would be admin/password .

The first page shown is the Master Realm configuration page. What is a Realm ? Here is the official definition:

A realm manages a set of users, credentials, roles, and groups. A user belongs to and logs into a realm. Realms are isolated from one another and can only manage and authenticate the users that they control.

A Realm is an abstraction inside Keycloak that holds configuration details. The Master Realm is the main Keycloak Realm . A user with access to it can interact with any other Realm . It is recommended not to use this Realm to authenticate other apps. Just use it to configure Keycloak itself.

The first thing we’ll do is create a new Realm . It will hold the configuration details for both of our applications. This include:

User database

Authentication policies

Allowed domains

We do this by clicking the Add realm button, found while hovering over the Realm select box.

Give the Realm a name and move on to the Realm configuration page. There are a lot of configurations that we can modify from here, to change how the users will interact with the service. Some of the most interesting are:

Login tab: add functionalities to the Realm like:

User registration.

Let the user update their username .

. Allow the “Forgot Password” flow.

Activate the “Remember me” option.

Activate the “Verify email” choice.

Allow the user to login using his email as its username.

as its username. Require SSL (set this in production always).

Email tab: add credentials for an SMTP server. We use emails to:

Validate user accounts

Run the forgot password flow

Run the recover password flow

Etc.

Theme tab: we can modify the theme of our login page. I won’t go deeper into how to create a new theme (maybe in another post). Just know that you can modify this theme however you like.

Tokens tab: we can modify the expiration times of the different tokens exchanged through the different authentication flows.

Client section: is used to add applications that can use this Realm .

Identity Providers section: is used to add external identity providers, like social networks, to authenticate our users.

User Federation section: is used to add external LDAP or Kerberos user databases.

Users section: gives us access to the whole user list handled by Keycloak.

And more.

On the main Realm configuration page, click the User-Managed Access toggle to enable users to manage their accounts. This option will let the user of our application manage their accounts on Keycloak’s account management console. Don’t forget to click Save before leaving this page. Then click on the Login tab and toggle the User Registration option. Save your changes.

Next, go to the Clients section. Click the Create button on the top right corner of the table to create a new one.

Give it a name like react-app-1 and its root URL http://127.0.0.1:3001 . Do the same for the other app.

The client configuration let us fine-tune the different authentication flows. The only value we’ll modify is the Login Theme . Select the keycloak option. Here is where you’ll configure your custom theme when you create yours. Leave the other parameters on their default values. Save your changes.

Let’s see what happens now when we try to access one of our React apps.

Cool, now we see the login form, and if we click the Register button, we can fill the form to create a new user. Try to create a new user, and if the data you entered is right, you’ll be redirected back to the app, greeted with a lovely welcome message.

User data

How do we know if the authentication flow worked?

After the user authenticates, we can access his information through the Keycloak client. By default, some info is sent in the JWT (JSON Web Token) and is accessible immediately. You can log the keycloak.idTokenParsed object to see the values available:

{

"jti": "58838d2a-d86c-4a01-a926-9cf0d57fc556",

"exp": 1563410747,

"nbf": 0,

"iat": 1563410447,

"iss": "http://127.0.0.1:8080/auth/realms/React%20App",

"aud": "react-app-1",

"sub": "e4668f11-903c-4c79-953b-2f06bb3ee1f5",

"typ": "ID",

"azp": "react-app-1",

"nonce": "c8c20eeb-458c-4a47-8128-7759ac1e3493",

"auth_time": 1563410179,

"session_state": "55a07b16-514c-4faf-97b7-212fa6485674",

"acr": "0",

"email_verified": false,

"name": "Example User",

"preferred_username": "example",

"given_name": "Example",

"family_name": "User",

"email": "user@example.com"

}

If you want to know more about how JWT works visit this page.

Let’s edit the App component to take advantage of this new information.

If we need more information about the user not found on the idToken we can use the keycloak.loadUserProfile() method.

Another cool feature of Keycloak is that it provides us with a user account management page. Let’s edit the Welcome component to add a button that we’ll redirect the user to their account management page.

https://gist.github.com/guzmonne/1d32b3250eed36073e39c538ac006004

More than one app

Until now, we have entirely forgotten about our other React app. Let’s see what happens when we open it.

What? Why are we getting authenticated?

Because both applications use the same Realm to authenticate users, this is the beauty of having keycloak as a single sign-on solution. Our user can now authenticate to all the clients configured on the same Realm , without having to re-enter his credentials. And, we don’t have to handle the user flows for each of our applications.

How do we logout the user? We use the keycloak.logout() method. Let’s try it out by modifying our Welcome component once more.

We’ve added a new button with an onClick handler to de-authenticate the user. Click it, and the app will display the login page. And, the user will also be de-authenticated from every other app on the Realm . Check the other React app, and you’ll see that the user has also been logged out.

Conclusion

We can implement many other features with Keycloak. What I wanted to show was how simple it is to add authentication to our apps so that we can focus on business logic.

The examples are web applications, but we can use this authentication flows with any application, for example, mobile apps.

You can find the code repository here: