Providing authentication and authorization for non-public-facing components of your application is an important part of many systems. All major Scala frameworks come equipped with some native tools for doing that, with complexity and comprehensiveness ranging from basic HTTP scheme with Akka HTTP’s SecurityDirectives to numerous Play plugins like Deadbolt 2 or Silhouette. However, actually getting what you need out of some of those can be difficult, and having to relearn them for every new framework provides additional overhead when moving to an unfamiliar tech stack.
Enter Keycloak server. What is it? To quote the authors:
Keycloak is an open source Identity and Access Management solution aimed at modern applications and services. It makes it easy to secure applications and services with little to no code.
It brings to the table virtually every feature you might want regarding authentication and authorization of users. Some of these include:
And many others.
Today, we’ll learn how to set up your own Keycloak server and use it to secure a React-based browser app; in the next part of this series, we’ll look at integrating it with a Scala backend. Let’s get started!
There are multiple ways of hosting your own Keycloak instance. If you’d like to go the classic way, you can download
the distribution file from https://www.keycloak.org/downloads.html and run the
bin/standalone.sh script. However,
if you’re a containerization fan like me, you’ll find that a
jboss/keycloak image has been provided in the Docker Hub.
In this case, there are three things you’ll need to know:
With this in mind, you can start the container:
docker run -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -e DB_VENDOR=H2 jboss/keycloak
Once the container starts, go to http://localhost:8080/auth/admin and log in using the credentials provided (admin/admin). This is the page you should be seeing:
What you’re seeing on the page above is the default (master) realm. A realm is the domain in the scope of which several types of entities can be defined, the most prominent being:
The master realm serves as the root for all others. Admins in this realm have permissions to view and manage any
other realm created on the server instance. Keycloak authors do not recommend using the master realm to actually
manage your users and applications (it is intented as space for super-admins to create other realms), so let’s
start by creating a new realm for our app. Mouse over the realm name in the top left
corner of the console and hit the
Add realm button. The only thing you need to specify for the new realm is
its name - let’s go with
Notice that you can now use the top left dropdown to switch between realms.
For simplicity, we’re going to stay with the default SSL mode, which is “external requests”: it means that Keycloak can run over HTTP as long as you’re using private IP addresses (localhost, 127.0.0.1, 192.168.x.x, etc.), but will refuse non-HTTPS connections on other addresses. You can find the details for SSL configuration in Keycloak documentation; if you’d like to use a trusted CA certificate in place of a self-signed one, you can get it easily with Let’s Encrypt by following these instructions.
The next thing to do is to define a test user for our new realm. Make sure that MyDemo realm is selected,
go to Users tab and hit
Add user. For now the only thing you need to provide is the username, let’s call him John:
After creating the user, you’ll need to set up his password. Go to Credentials tab, enter the new password twice and hit Reset Password (in a real application, you can either allow users to self-register or configure an SMTP server and use the Verify Email and Update Password actions to enable admin-created users to choose their passwords themselves).
To check if the new user works, open a new incognito window in your browser,
go to http://localhost:8080/auth/realms/MyDemo/account and try logging in with
john and the password you provided earlier. Since we left the
option turned on when resetting the password, you’ll be asked to provide a new one
on first login. Afterwards you’ll be taken to your account management panel:
Among other stuff, this allows you to provide your profile information (which may or may not be enforced by the admin),
change your password, and see all your active login sessions. For now, let’s update the
Last name fields with whatever values you like, then get back to the admin window.
The final step of the initial server configuration is creating a client. Clients are browser apps and web services that are either allowed to initiate the login process or provided with tokens resulting from earlier logins. Today we’ll be securing a React-based frontend, so let’s go to the Clients tab and hit the Create button:
In addition to client name (
my-react-client), we’ve also provided the root URL of the application we’re about to create (http://localhost:3000/). Hit
Save and you’ll be taken to the client details panel.
The amount of options visible here can be a bit daunting, but really there are just three that are important
at the moment. The first is
Access Type with three possible values:
Bearer-only- this is for services that rely solely on the bearer token included in the request and never initiate login on their own; it’s typically used for securing the backend
Confidential- clients of this type need to provide a secret in order to initiate the login process
Public- since we have no real way of hiding the secret in a JS-based browser app, that’s what we need to stick with
Valid Redirect URIs - this is the URI pattern (one or more) to which the browser can redirect after
completing the login process. Since we picked public access type for our client (and thus anyone can request to initiate
the login process), this is especially important: in a real app, you need to take care to make this pattern as restrictive
as possible, otherwise you open your system to a phishing exploit! However, for dev purposes you can just leave it at default.
The last of the important options is
Web Origins, which governs CORS requests. Again, for dev purposes the default value
One last thing we’ll need is the client configuration to use with our app. Go to the
Installation tab and select
Keycloak OIDC JSON as format:
Download this JSON and keep it, we’ll need it later.
With this, your Keycloak server setup is complete - let’s start whipping up our frontend code!
We’re going to create a simple React-based app that allows the user to navigate between two components: one public and one that requires logging in. Instructions will be given step-by-step, for the benefit of those readers who had no previous exposure to React. If you’re eager to browse through the finished code, you can just download it from my GitHub repo.
I’m going to assume you have
npm installed - if not, you can get it from here.
We’ll be using the
create-react-app script, so install it as well if you don’t have it yet:
npm install -g create-react-app
Now we can use it to create the template for our application:
As a first step, we’ll need to add some dependencies. Open
package.json and add the following two items:
Run the following to download the new dependencies:
Keycloak server (it’s hosted at
/auth/js/keycloak.js), which has the added benefit of not having to worry
about mismatched versions. However, React doesn’t play nice with remote URL imports, so it’s easier to do it this way.
Also worth mentioning: 4.0.0 is the first version of Keycloak to use ES6 Promises instead of homegrown promise-like objects. If you have to work with an older version for any reason, Raymond DeCampo has a wrapper that could help.
Moving on: let’s replace the contents of
src/App.js with our skeleton:
As you can see, this is just a Router providing navigation between two other components. Let’s add the first of those,
Nothing particularly fancy here, just some generic text. The next one should be a bit more interesting - put it at
As soon as the component is mounted into the DOM, we create the Keycloak object by providing client configuration:
Remember the JSON I told you to download from the admin panel? Put it into
public/keycloak.json to make the above work.
Keycloak.init returns a promise; once it’s completed, we can update the component state to make it rerender its contents:
login-required is one of two possible values to be passed as the
onLoad parameter; it will authenticate the client
if the user has already logged in to Keycloak, or redirect the browser to the login page if he has not. The other option
check-sso: it will only authenticate the client if the user has already logged in, otherwise the client will remain
unauthenticated without automatic redirection.
Time to check it out - run
npm start and your browser should open automatically:
Follow the secured link and you’ll be redirected to the login page:
Log in as
john with the password you specified earlier, and voilà:
You will find that you can now navigate between the two components without having to log in again. If you’d like to know a bit more about the magic that happened here, I recommend reading through the documentation on OpenID Authorization Code flow, which Keycloak is using by default (Implicit and Hybrid flows are also supported).
As a test, open a new incognito window and try going through the login process again, but use
localhost - since the redirect URI pattern we specified in the admin panel earlier only included the latter
and not the former, you will get an error on the login page.
Let’s expand our app a little bit by adding the logout functionality and some user data extraction. We’ll start with
the latter - add the following as
This component accepts a Keycloak instance from its parent, then uses the
loadUserInfo method to extract the user’s data.
Now for the logout button, place the following in
Similarly, this accepts a Keycloak instance from the parent, then uses its
logout method. Note that it has to be called
last - otherwise it would redirect you to the login form again.
Let’s include these new components in
As expected, clicking the logout button forces you to have to log in again the next time you try to access the Secured component.
This concludes the demonstration for today - you can see now how easy and quick it is to provide front-end authentication with Keycloak. Don’t miss the second part of this series, where we’ll look into securing your backend using bearer tokens!