What you’ll need to follow along

To gain some understanding about OpenID Connect and Keycloak no tools are needed. If you however want to experiment and follow along yourself on how to get started with OpenID connect and Keycloak you’ll need some basic tools.

Make sure to have the following installed:

  • JDK 8+
  • Maven
  • IDE/Text editor
  • Docker or Podman

Source code can be found here github.com/GustafNilstadius/OIDC-Keycloak-Vert-X-example.

Background

The predecessor of OpenID Connect is OAuth2.0 (“Open Authorization” version 2). As the name suggest, OAuth2 is used for authorization. Most of us have probably encountered OAuth2 at some point in time, often recognized by the “Log in with” e.g GitHub, Google or Facebook account (although many of these now use OpenID Connect). The foundational functionality in OAuth2 is to retrieve an access token can be used to access data on the resource server (see image bellow). OAuth2is not meant to be used for authentication.

OAuth2 specifies that the access token should be treated as opaque, meaning the token can’t be interpreted by the client (our application server). Since the access token and is opaque, no information about the resource owner is available to the client application server.

OAuth2 should not be used for authentication or for AuthZ, role base access control. The access token is only supposed to be used to identify and authenticate against the resource server and not on the communication between the resource owner and the client application server.

OpenID Connect

OpenID Connect (OIDC) solves many of the above problems of OAuth2, primarily the lack of information about the resource owner (user) and authentication. This enables OpenID Connect to be used for Single Sign On (SSO). In contrast to OAuth with the opaque tokens, OpenID Connect heavily relies on JWT. This in turn makes the tokens readable by the client application server and allows for payload/metadata to be included.

JWT and the payload of the JWT enables the ability for AuthZ and role based access control on the client application server, and to verify the signature and validity of the JWT without a round trip to the authorization server (Keycloak in our case).

OpenID Connect is based on OAuth and is backwards compatible with a client application server that doesn’t yet support OAuth. The data models look the same between OAuth2 and OpenID Connect for the most part except that an ID token is returned in conjunction with the access token (in step 4 of bellow image). The ID token contains even more data about the person and enables for OpenID Connect to include information such as links to profile images, home address or any other information linked to the resource owner/user in question.

Most OpenID Connect authorization servers has the functionality to publish the configurations for the OpenID Connect service. For faster development and deployment, this is the case with Keycloak, and it simplifies setup immensely.

How OpenID Connect it works

  1. Resource owner triggers/initiates the authorization request, this could be by trying to access a restricted resource without a valid session/token or by clicking on a “Login” button.
  2. Resource owner completes the authentication/authorization on the OpenID Connect enabled service and is redirected back to our application with an authorization grant code.
  3. The authorization grant code is exchanged by our server.
  4. Our client application server receives the access token + ID token.

OAuth Authorization Code Flow

Keycloak

Keycloak describes itself as “Open Source Identity and Access Management”. That pretty much sums it up. Keycloak makes setting up identity brokers and user federations a breeze. Mainly for this guide, Keycloak is OpenID Connect compatible (OpenID Connect certified).

Setup

Now we have a basic understanding of OpenID Connect and Keycloak. Let’s get is set up and test it out.

Keycloak in docker

The first step we need to do is get Keycloak running locally. It’s a breeze to get it running with OCI containers. In this example I choose Docker, but feel free to use any OCI compliant container host.

docker run -p 8989:8080 -dt -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:19.0.2 start-dev

Let’s take a quick look at the command.

  • -p 8989:8080: We bind the host port 8989 to 8080 in the container, the default port of Keycloak.
  • -e KEYCLOAK_ADMIN=admin: We set the environment variable KEYCLOAK_ADMIN to admin. This will be out admin username for Keycloak.
  • -e KEYCLOAK_ADMIN_PASSWORD=admin: Setting the environment variable KEYCLOAK_ADMIN_PASSWORD to admin. This will be the default password for our admin user. This should be changed.
  • quay.io/keycloak/keycloak:19.0.2: The image we are going to run. Version 19.0.2 is the latest as of the time of writing this.

Note: we have not specified a database. Keycloak will use an embedded in memory database with no persistence, meaning all data will be lost if you shut down the container.

Configure Keycloak

You should now have Keycloak running on localhost:8989. Head on over and login to the admin console with the credentials provided when starting the container.

1. Create a realm

Keycloak uses what they call ‘realm’ to separate environments. Everything we do in Keycloak has to exist in a realm. Let’s go ahead and create a realm called dev. Navigate to Realm Settings in the menu and go to the Login tab to enable user registration.

Create realm in Keycloak drop-down.

Create 'dev' realm in Keycloak.

Enable user registration in Keycloak.

2. Create and configure a client

Client in this context is not to be confused with our client application server. A client in Keycloak represents an interface for one or more client applications to communicate with. A client can have different scopes and be able to see different data depending on the configuration and the need of the client applications. Some client applications might require extensive data on the resource owner (user) and some might not.

We will in this demo leave most things default and configure the bare minimum to get up and running with Keycloak and OpenID Connect.

  1. Make sure you are in the dev realm.
  2. Select client in the left menu and click Create client.
  3. Creating the client
    1. Client type OpenID Connect.
    2. Client ID dev-client.
    3. (Next page)
    4. Client authentication to on.
    5. Create.
  4. Navigate to your recently created client (should be redirected to it after the creation) and enter the Credentials tab. Note the client secret, you’ll need it to use the client.
  5. In the same client, navigate to the Settings tab and scroll down Access settings.
    1. Set Root URL to http://localhost:8888
    2. Set Valid redirect URI to /*
    3. Set Home URL to http://localhost:8888/index.html
    4. Save

Now your Keycloak is all set up and ready for use!

You can also explore the Keycloak OpenID Connect discovery endpoint on localhost:8989/realms/dev/.well-known/openid-configuration. This will be consumed by our application later to configure the OpenID Connect connector.

Client application server

The last piece of the puzzle is our client application that will use OpenID Connect to authenticate users. Source code can be found here github.com/GustafNilstadius/OIDC-Keycloak-Vert-X-example.

Our application is written in the event driven Java framework Vert.X. Vert.X is an alternative to Spring Boot and offers very high concurrency and a non-blocking API.

Configure the application

Navigate to the conf/conf.json file.

Enter the client secret from the previous step and save. An example is given below, note that your OIDC_CLIENT_SECRET will differ. OIDC_DISCOVERY_URL points to the base path for the OpenID Connect discovery path, this does not need changing.

{
  "OIDC_CLIENT": "dev-client",
  "OIDC_CLIENT_SECRET": "LwwKkgK63RAGYW53rTmhT8Givj1mzpmn",
  "OIDC_DISCOVERY_URL": "http://localhost:8989/realms/dev"
}

Compile and package application

To package your application:

mvn clean package

Run the application

To run your application:

java -jar target/redpill.linpro.bbl.oidc.demo-1.0.0-SNAPSHOT.jar --conf conf/conf.json

An exception might present itself to warn that Keycloak supports some cryptographic protocols that Java doesn’t. This can be ignored.

The server should now be running on port 8888, head over to http://localhost:8888/ to explore the application. It’s a very very simple website.

Evaluating the code.

Navigate to the file src/main/java/com/gustafn/redpill/linpro/bbl/oidc/demo/MainVerticle.java.

Session handler

For OpenID Connect to function properly in our case. In Vert.X we create a non-clustered session store and link it to a session handler. We then register the session handler on the router to handle HTTP requests.

Router router = Router.router(vertx);
LocalSessionStore localSessionStore = LocalSessionStore.create(vertx);
SessionHandler sessionHandler = SessionHandler.create(localSessionStore);
/*....*/
router.route().handler(sessionHandler);
Configure OpenID Connect - Keycloak

OpenID Connect is an extension to OAuth2, so we use a OAuth2 connector to create the connection and OIDC handler. You explore the OpenID Connect service discover endpoint, the Keycloak OpenID Connect discovery endpoint is available here: localhost:8989/realms/dev/.well-known/openid-configuration.

// Options for the OpenID Connect Vert.X client.
OAuth2Options clientOptions = new OAuth2Options()
  .setClientId(config().getString("OIDC_CLIENT"))
  .setClientSecret(config().getString("OIDC_CLIENT_SECRET"))
  .setSite(config().getString("OIDC_DISCOVERY_URL", "http://localhost:8989/realms/dev"));

// Initialize the Keycloak connection and use the OpenID Connect service discovery to create the OIDC handler.
KeycloakAuth.discover(
  vertx,
  clientOptions)
  .onSuccess(oAuth2Auth -> {
    ...
    // Protect all routes starting with '/private' with out OIDC handler.
    router.route("/private/*").handler(oauth2handler);
    ...
   })
  .onFailure(startPromise::fail);

OpenID Connect with Keycloak and Vert.X in practice

With everything up and running, head over to http://localhost:8888/ and we’ll start exploring how it all works in practice.

To follow along, open the developer tools in your browser (usually F12 button will open it) and go to the Network tab.

Pressing the Click here for secret stuff. link will try to direct the user to http://localhost:8888/private/index.html.

Since the path is under the /private path authentication is required for access, and since we are not logged in we will be redirected to Keycloak to authenticate, this triggers/initiates the authorization request.

The response from our application server is a 302 with a redirect location.

The redirect location URL contains some query parameters that tells Keycloak what we want to do and to initiate a OpenID Connect authentication and where to redirect the user after successful authentication.

This should be seen in your developer tools in your browser (together with other requests).

HTTP/1.1 302 Found
location: http://localhost:8989/realms/dev/protocol/openid-connect/auth?state=jpGd7FWg&redirect_uri=http%3A%2F%2Flocalhost%3A8888%2Fcallback&scope=openid&response_type=code&client_id=dev-client

If you enabled User registration in the configuration of Keycloak (see above) you should be able to create a user. Follow the instructions to create a user and as you click Register you will be redirected back to our application.

This is visible as two logs in our browser developer tools.

First a response form Keycloak with a 302 redirect. In the Location header we can see the redirect URL that links back to our callback endpoint.

HTTP/1.1 302 Found
...
Location: http://localhost:8888/callback?state=jpGd7FWg&session_state=fca13ce5-30f0-47da-8bb7-770d8ebd0473&code=b79a5345-3379-470c-9781-19fb3e7cd568.fca13ce5-30f0-47da-8bb7-770d8ebd0473.8bb01f13-9bcb-4abe-a3ba-02374af1f76d

This should trigger a call to the URL given in the Location header. With the code given as a query parameter in the Location header, our application server can retrieve a OpenID Connect Access token and ID token from the Keycloak server. You are now authenticated and can access the protected page.

By navigating to localhost:8888/private/account (or clicking User data) you can inspect the ID token, and the default data included in the token.

Conclusion

OpenID Connect with the help of Keycloak is a quick way to get started protecting your service (whether written in Vert.X or not). Keycloak makes the job a breeze and OpenID Connect is flexible extension of OAuth2.

Gustaf Nilstadius

Senior Java Consultant at Redpill Linpro

Gustaf started at Redpill Linpro in 2020 after spending multiple years abroad working in Silicon Valley. Gustaf is specialized in micro-services and the Vert.X framework.

Containerized Development Environment

Do you spend days or weeks setting up your development environment just the way you like it when you get a new computer? Is your home directory a mess of dotfiles and metadata that you’re reluctant to clean up just in case they do something useful? Do you avoid trying new versions of software because of the effort to roll back software and settings if the new version doesn’t work?

Take control over your local development environment with containerization and Dev-Env-as-Code!

... [continue reading]

Ansible-runner

Published on February 27, 2024

Portable Java shell scripts with Java 21

Published on February 21, 2024