Utmost Protection with OpenId Authentication 🔒

API security is so important for any system as it exposes sensitive data like medical, financial, personal etc for public consumption. So resource security and authentication takes an uttermost significance in configuring any enterprise API gateway. Here I am guiding you through the steps to configure the Kong API gateway reliably and securely with it’s OpenId connect plugin.

OpenID is an authentication protocol based on the OAuth 2.0 family of specifications which enables an end-user to communicate with a relying party. This communication is done through the exchange of an identifier. It enables clients to verify the identity of the end-user based on the authentication performed by an authorization server, as well as to obtain basic profile information about the end-user in an interoperable and REST-like manner. You can read more on OpenId in the wiki.

OAuth 2.0 is designed only for authorization, for granting access to data and features from one application to another. OpenID Connect (OIDC) is a thin layer that sits on top of OAuth 2.0 that adds login and profile information about the person who is logged in

Below is the overview of basic flows in OpenId protocol.

     +--------+                               +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+

Grant Types

Grant types are a way to specify how a client wants to interact with Identity server. Here we are discussing the two of the commonly used grant types, client credential grant and refresh token grants. Based on these different grants, there are few modes of authentications for the clients.

Client Authentication methods that are used by clients to authenticate against the authorization server when using the token endpoint. During client registration, the system admin may register the client with one of the authentication methods. So to enable to the maximum protection for our system, we decided to configure the Kong API gateway with it’s OIDC plugin with client_secret_jwt based authentication. You can read my previous publication to refresh your knowledge on the Kong API gateway.

With client_secret_jwt, all the authentication flows are based on OIDC client credentials grant specifications and JWT token exchanged in these flows are encrypted using an HMAC SHA algorithm.

Kong OIDC Plugin

Kong’s OIDC plugin functionality is bit different from the standard OpenId flow and it is more user friendly as it is enhanced a little to reduce the workload from the client side. Here I am using the RedHat SSO server (keycloak) as the authorization server in my OpenShit container platform. But the concept is same for any other platform with a different authorization server.

Enhanced OpenId flow provided by the Kong OIDC Plugin

In the above diagram you can see that there is no any specific token acquire flow as such. Instead it is handled by the Kong OIDC plugin during the normal API request when the credentials (client is and secret) are passed as an extra request headers.

curl https://{{hostname}}/api/service-endpoint/resource1 \
-H’Authorization: Basic {base 64 encoded {client id:secret}}’

Then the Kong OIDC plugin will do the authentication against the SSO server, obtain the access token, inject it in the header and pass the API request to back-end on behalf of the client. The client does not need to make a separate API request to get the access token from authorization server which is then being used in the subsequent requests as specified in the standard OpenId flow. But at the moment, Kong does not support client_secret_jwt based authentication with this flow, which is a limitation for our requirement.

But this can be achieved with a simple workaround to provide a standard OpenId protocol based flow to the end user.

Request flow for Kong OIDC plugin with client_secret_jwt authentication

The above flow can be configured as follows.

  1. Configure a simple proxy pass in Kong to redirect the authentication request for access token generation to the SSO server.
kong proxy pass to sso server

2. Once the client obtain the access token, authentication the token against the SSO server using the Kong OIDC plugin.

How to generate the token

Below are the steps to generate the JWT using an HMAC SHA algorithm, such as HMAC SHA-256 using the client credentials received from the system admin after on-boarding the new client in the SSO server. The HMAC (Hash-based Message Authentication Code) can be calculated either using the octets of the UTF-8 representation of the client secret as the shared key or the public and private key pair.

The JWT MUST contain at-least the following claim values. Please refer this for more detailed information on OpenId client authentication.

{
“jti”: “{unique id}”,
“sub”: “{client-id}”,
“iss”: “{client-id}”,
“aud”: “{Audience URL}”,
“exp”: {expire time in epoch scale for the ID Token}
}

The header and the payload is concatenated and signed using the client secret.

JWT token generation

This generated token is used in the payload of the below given sample requests to obtain the access token from the token endpoint.

Let the token endpoint of the Kong API gateway be https://{{hostname}}/api/service/token

With Client Credentials Grant

curl -XPOST ‘https://{{hostname}}/api/service/token' \
-H’Content-Type: application/x-www-form-urlencoded’ \
— data-urlencode ‘grant_type=client_credentials’ \
— data-urlencode ‘client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer’ \
— data-urlencode ‘client_assertion={{client_secret_JWT_token}}’

client_secret_JWT_token: The above generated JWT token with client credentials

With Refresh Token Grant

curl -XPOST ‘https://{{hostname}}/api/service/token' \
-H ‘Content-Type: application/x-www-form-urlencoded’ \
— data-urlencode ‘grant_type=refresh_token’ \
— data-urlencode ‘refresh_token={{refresh_token}}’ \
— data-urlencode ‘client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer’ \
— data-urlencode ‘client_assertion={{client_secret_JWT_token}}’

Sample Response

{
“access_token”: “ImtvbmctdGVzdC11c2VyIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQta29uZy10ZXN0LXVzZXIiLCJjbGllbnRBZGRyZXNzIjoiMTcyZDy7iQKAD9b3IlZ8EKfo0Kc9gS7rpuh00qBzNafUGFeVwSpNe”,
“expires_in”: 14400,
“refresh_expires_in”: 86400,
“refresh_token”: “eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIyZDRkMDhiNi04MGY2LTQ1ZWMtODILXRlc3QtdXNlciI6eyJyb2xlcyI6WyJ1bWFfcHJvdGVjdGlvbiJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wm9maWxlIl19fSwic2NvcGUiOiJwcm9maWxlIGVtYWlsIn0”,
“token_type”: “bearer”,
“not-before-policy”: 0,
“session_state”: “d0090d58–4fd0–4b59-b0c1-fe37c098b5f7”,
“scope”: “profile email”
}

The access token received above can be used to trigger API requests to any ingress endpoint in the Kong gateway which is configured with the OIDC plugin. Upon the successful validation of the token by the OIDC plugin, the user will be allowed to consume the resources from the back-end service.

Thank You for Reading!

Senior Software Engineer | BSc (Hons) Engineering | CIMA | Autodidact | Knowledge-Seeker