In this post we are going to configure Keycloak for OAuth2 Access Code flow and connect it to IBM API Connect as a third-party Oauth2 provider.

The article includes steps to:
1. Install Keycloak
2. Configure Keycloak for OAuth2 Access Code flow
3. Creating a Redirect URI page
4. Test the OAuth2 flow using separate requests
5. Test the OAuth2 flow using Postman
6. Connect Keycloak to IBM API Connect
7. Test an API with OAuth2 protection

1. Installing Keycloak

We are going to run Keycloak in a docker container
docker run -d -p 8080:8080 -p 8443:8443 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin jboss/keycloak

Keycloak interface will be available at:
https://HOST_NAME:8443
Credentials: admin/admin

2. Configure Keycloak for OAuth2 Access Code flow

Create a Keycloak realm
A realm manages a set of users, credentials, roles, and groups. Realms are isolated from one another and can only manage and authenticate the users that they control.

Creating realm in Keycloak

Create a Client
Clients are entities (apps) that can request authentication of a user.

Creating Client in Keycloak

Configure client's settings. In Valid Redirect URIs insert your callback URL (a page where access code will be redirected to). If you don't have this page you can create one based on Creating a Redirect URI page

Configuring the Client for confidential access type

Write down your client Id and Secret. We will use those values later.

Getting Client Id
Getting Client Secret

Create a Role
Now we are going to create a Client's role. Roles identify a type or category of user. Keycloak often assigns access and permissions to specific roles rather than individual users for a fine-grained access control.Keycloak offers three types of roles:

  • Realm-level roles are in global namespace shared by all clients.
  • Client roles have basically a namespace dedicated to a client.
  • A composite role is a role that has one or more additional roles associated with it.

We will create a Client role. Press "Add Role" on the Roles tab of the client.

Adding a Client role

Provide a name to the role:

Creating a Client role

Create a User
Users are entities that are able to log into your system. They can have attributes associated with themselves like email, username, address, phone number, and birth day. They can be assigned group membership and have specific roles assigned to them.

Create a user and set "Email Verified" to ON.

Creating a User in Keycloak

Provide a password to the user. Set "Temporary" to OFF.

Setting user's password

Create Role Mapping for the user
A user role mapping defines a mapping between a role and a user. A user can be associated with zero or more roles. This role mapping information can be encapsulated into tokens and assertions so that applications can decide access permissions on various resources they manage.

Go to Role Mapping tab for the user and assign the Client role created before.

Create a scope
Scope is a mechanism in OAuth 2.0 to limit an application’s access to a user’s account. An application can request one or more scopes, this information is then presented to the user in the consent screen, and the access token issued to the application will be limited to the scopes granted.
Scope allows a client application to request more or fewer claims or roles in the access token, according to the application needs.

Creating a Scope in Keycloak

Assign the scope as an optional client scope. Optional client scopes are applied when issuing tokens for this client, but only when they are requested by the scope parameter in the authorization request.

Assigning an Optional Client Scope

At this point we have configured everything we need on the Keycloak side.

3. Creating a Redirect URI page

This step is optional and only needed if you do not have a Redirect URI yet and would like to test your flow manualy.
We are going to deploy a simple HTML page on Nginx. This page will show us an access_code returned after /auth call. This access_code will be used after to get a token.

Run Nginx in docker. This command will expose TCP port 8085 on the host. The web content should be placed under /root/html. You can use another port or folder to place the content.
docker run --name some-nginx -d -p 8085:80 -v /root/html:/usr/share/nginx/html nginx

Generate index.html with the following content and put it under /root/html

<html>
  <head>
        <link rel="stylesheet" type="text/css" href="style.css" />
  </head>
  <body>
    <div>
      <h1 id="msg">Your access code</h1>
      
      <div id="container"></div>
    </div>

    <script>
      var container = document.getElementById('container');
      var my_html = '';
      var url = window.location.search;
      //url = '?error=invalid_request&error_description=Invalid+scopes%3A+apiconnect'

      var query = url.substr(1);
      var result = {};
      query.split("&").forEach(function(part) {
        var item = part.split("=");
        result[item[0]] = decodeURIComponent(item[1]);
        container.innerHTML += '<b>'+item[0]+': </b>'+result[item[0]] + '<br>';
      });
      
    </script>

  </body>
</html>

Generate style.css and put it under /root/html

body {
  background: white;
  color: #323232;
  font-weight: 300;
  height: 100vh;
  margin: 0;
  display: flex;
  align-items: top;
  justify-content: center;
  text-align: center;
  font-family: Helvetica neue, roboto;
}

img {
  width: 56px;
  height: 48px;
}

h1 {
  font-weight: 200;
  font-style: 26px;
  margin: 10px;
}

Now you can set Valid Redirect URIs for the Client as http://YOUR_HOST:8085

4. Test the OAuth2 flow using separate requests

We are going to test our configuration using access_code flow.

access code flow
  1. Request an access code using /auth endpoint
  2. Get an access_code back
  3. Use access_code to request a token using /token endpoint
  4. Get a token back
  5. Validate our token using /introspect endpoint
  6. Get a response with a status for our token (if it active or not)

Lets get our endpoints for OAuth flow. Open Realm settings and press "OpenID Endpoint Configuration" button.

Endpoints for OAuth2.0

We will need these three endpoint:

/auth, /token and /introspect endpoints

Step1: Request an access code
Open this link in a browser. Put your values for the attributes.
https://keycloak:8443/auth/realms/apic/protocol/openid-connect/auth?response_type=code&redirect_uri=YOUR_HOST:8085&scope=apiconnect&client_id=api-services

You will be forced to authenticate:

Provide credentials to access the Client

After successful authentication an access code will be sent to your redirect URI:

Getting access_code on your Redirect URI page

Step2: Request a token
Copy the access_code from the page and use it in the following request for a token.
curl -v -k -u CLIENT_ID:CLIENT_SECRET -X POST -d 'grant_type=authorization_code&redirect_uri=YOUR_HOST:8085&code=YOUR_ACCESS_CODE' 'https://keycloak:8443/auth/realms/apic/protocol/openid-connect/token' | jq

An example of a response with a token

Step3: Introspect the token
Copy the token from the response above and use it in the following request to validate the token.
curl -v --data "client_secret=CLIENT_SECRET&client_id=CLIENT_ID&username=USER_NAME&token=TOKEN_VALUE" https://keycloak:8443/auth/realms/apic/protocol/openid-connect/token/introspect -k| jq

An example of a response from introspect url

At this point we have tested our OAuth flow and we are able to get a valid token now.

5. Test the OAuth2 flow using Postman

It is very easy to test such flows with Postman as it has all required redirects implemented.

Create a new request in Postman and switch to Authorization tab. Press "Get New Access Token" button.

Postman: get new access token

Fill all fields with your data and press "Request Token"

Postman: requesting token

Postman will return a token:

Postman: response with a token

6. Connect Keycloak to IBM API Connect

In this section we will configure IBM API Connect to use Keycloak as an external OAuth provider to generate and validate tokens for our API.
I suggest you have an API implemented already. Futher steps are about how to add OAuth security to an existing API.
We will provide our /auth, /token and /introspect urls to API Connect configuration. After that, API Connect will use /auth and /token to get a token for an application. And /introspect to validate the token on APIs' calls.
We are going to configure OAuth Provider in API Connect Manager console.

Open Resources menu and add a "Third party OAuth provider":

Adding 3rd party OAuth Provider in IBM API Connect

Name it and choose "Access code" as a grant type:

Configuring an OAuth provider in IBM API Connect

Provide details related to your OAuth provider.

Configuring endpoints for 3rd party OAuth Provider in IBM API Connect

Add your scopes on the Scopes tab:

Adding scopes for 3rd party OAuth Provider in IBM API Connect 

Following the steps above we have created a 3rd party OAuth resource in IBM API Connect. Now we need to link it with a Catalog.

Open "Settings" menu for a Catalog (i.e. Sandbox) and choose our configured OAuth provider on "OAuth Providers" tab. After that we can publish to this Catalog those APIs which use our OAuth Provider for authorization.

Linking an OAuth provider with a Catalog in IBM API Connect

On the next step we configure an API to use OAuth. Choose your OAuth provider on "Security Definitions" tab of the API.

Adding OAuth provider to an API in IBM API Connect

On the Security tab we should enforce OAuth authorization for the API:

Enforcing OAuth authorization for an API in IBM API Connect

After that all configuration is done and we can deploy our API to the Catalog.

7. Test an API with OAuth2 protection

Open IBM API Connect Developer Portal and find the deployed API there. As you can see it contains OAuth endpoints in the description.

API with OAuth security in IBM API Connect Developer Portal

Now send a request with a wrong token. The request will be rejected by API Gateway with an error.

Unauthorized request to an API in IBM API Connect

Lets provide a correct token and call the API again. Now we have got a successful response.

Successful response from an API in IBM API Connect