Keycloak now supports Authentication Context Class Reference parameter for different Level of Authentication. It means that you can define different level of authentication in a single flow.

oidc-bash

Our partner please-open.it has open sourced a little tool called oidc-bash.

https://github.com/please-openit/oidc-bash-client

This tool provides :

  • a set of commands for each operation possible with the openid connect protocol. Each command needs a set of parameters, and uses CURL, NetCat and JQ for all operations such as : token exchange, client credentials, implicit grant …
  • a great learning tool by looking at the source code. Each operation is done by using CURL requests with variables. This tool does not use any library.

Example :

./oidc-client.sh --operation client_credentials --openid-endpoint http://127.0.0.1:8080/realms/master/.well-known/openid-configuration --client-id oidc-bash --client-secret FiAzIhuTS0c4Bynb1CZuChURNntHMOCb
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJjY3cyRzY0MzVIM2g1cVRTU2FuVHFCUGJuMTl5eU1FOGFBNklpcTlzLXlFIn0.eyJleHAiOjE2Njc5NDEwNTQsImlhdCI6MTY2Nzk0MDk5NCwianRpIjoiN2RjY2QzYTEtZWI3ZC00YWFlLTk5YjgtYmEwM2NmZGMzZWE5IiwiaXNzIjoiaHR0cDovLzEyNy4wLjAuMTo4MDgwL3JlYWxtcy9tYXN0ZXIiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiYjY5YzVkODktYmZiNy00ZDA2LWE0OGYtYTI0OTUzNjVmYjM1IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoib2lkYy1iYXNoIiwiYWNyIjoic2ltcGxlIiwiYWxsb3dlZC1vcmlnaW5zIjpbImh0dHBzOi8vcGxheWdyb3VuZC5wbGVhc2Utb3Blbi5pdCIsImh0dHBzOi8vcGxheWdyb3VuZC5wbGVhc2Utb3Blbi5pdCoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtbWFzdGVyIiwib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoicHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiY2xpZW50SWQiOiJvaWRjLWJhc2giLCJjbGllbnRIb3N0IjoiMTI3LjAuMC4xIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LW9pZGMtYmFzaCIsImNsaWVudEFkZHJlc3MiOiIxMjcuMC4wLjEifQ.mXVWB-NSHxqJrA5OWRWoQfw_pK-KJJRDUOxmbX-oOUDPDIf5Yc7fbr-PVirAMo8JtwVnHAOeWWnjZGZeL2SpaqbGElijTOa9ofq8CC_MXhcZWP4SBF9WSixrTdHTukcaZhSdsRl8EBcd5R1aoJC2BFzSYFUM4xNUjPxfAPbH9mQLLPSYnQ7aqJfhyzUr5hN7IpV0si5-rUn-cGlc_TcOIkIOM82-cOoR8MFMcMUQFR1f2IJpkBdYPrJ960iMMTHOF3Son809Iz9KNUAvcfzn4Iw65JAAhyyWk9ovmhfHIWKM8L4seyF8bM4sxPQTpmoBV59S7BP-yHUNwdnV3LR9cw",
  "expires_in": 60,
  "refresh_expires_in": 0,
  "token_type": "Bearer",
  "not-before-policy": 0,
  "scope": "profile email"
}

playground

This tool comes from @sebi2706 :

https://github.com/please-openit/keycloak-playground

And available freely :

https://playground.please-open.it

It works with any Keycloak instance, including local instances or private ones. It uses keycloak.js library, and now has support for ACR.

All parameters are saved locally (by using local storage) :

Authentication Context Class Reference and Level Of Authentication with Keycloak

You can also generate an URL with all parameters :

https://playground.please-open.it?url=http://127.0.0.1:8080&realm=master&client=oidc-bash&scopes=&acr=%7B%22essential%22:true,%22values%22:%5B%22expert%22%5D%7D

Authentication Context Class Reference

https://ldapwiki.com/wiki/Authentication%20Context%20Class%20Reference

https://digital.nhs.uk/services/identity-and-access-management/nhs-care-identity-service-2/care-identity-authentication/guidance-for-developers/detailed-guidance/acr-values

https://openid.net/specs/openid-connect-core-1_0.html#acrSemantics

This optional parameter on authentication is used by the application to call for a specific level of authentication needed for the context.

Before this parameters, there was only 2 solutions :

  • have an optional non standard parameter, get it in a custom authenticator then applies it to an authentication flow
  • uses different clients.

Now, it is an official parameter with a supported implementation in Keycloak

Use it with oidc-bash and playground

There is 2 options :

  • claims parameters, with a json structure
  • acr_values directly

With oidc-bash, we added the flag –acr, just providing a comma separated list of values.

With playground, a JSON structure as described in the keycloak documentation :

claims= {
            "id_token": {
                "acr": {
                    "essential": true,
                    "values": ["gold"]
                }
            }
        }

Prepare Keycloak for different Level Of Authentication

Client

In your client, go to « advanced » then « advanced settings » :

Authentication Context Class Reference and Level Of Authentication with Keycloak

What is ACR to LoA ? As described in the spec could be a string, in Keycloak a Level Of Authentication must be an integer.

Define which ACR (Authentication Context Class Reference) value is mapped to which LoA (Level of Authentication). The ACR can be any value, whereas the LoA must be numeric.

Those levels of authentication will be discriminating for the authentication flow conditions.

Authentication flow

You have to create a new authentication flow, be careful with cookie as an alternative authentication execution ! It means that every check will be bypassed if the user is already authenticated.

Authentication Context Class Reference and Level Of Authentication with Keycloak

For each LoA, you have to create a conditional subflow. The condition is « Level of Authentication », add a configuration to the condition :

Authentication Context Class Reference and Level Of Authentication with Keycloak

Then all needed steps for this level of authentication.

In this example :

  • simple level does not need anything except the username
  • extended ACR needs a password.

Warning : keep the « browser » flow as a standard flow in Keycloak, only use this flow for clients by overriding the default configuration in the client configuration.

Check in the client

Directly in the token, the acr is added as a claim :

{
    "exp": 1667944469,
    "iat": 1667944409,
    "auth_time": 1667944349,
    "jti": "1da0191f-479f-4b1c-b543-1806de44996d",
    "iss": "http://127.0.0.1:8080/realms/master",
    "aud": "oidc-bash",
    "sub": "5eadd7c1-bd74-40e7-8377-54ff5e45f64c",
    "typ": "ID",
    "azp": "oidc-bash",
    "nonce": "a0f6c4d4-37c9-4c04-8e4f-cfff251f7176",
    "session_state": "74a56574-d14d-4f8a-8a5c-424eaceac849",
    "at_hash": "iMt6_oUbQ5cricbOgmrwIA",
    "acr": "expert",
    "sid": "74a56574-d14d-4f8a-8a5c-424eaceac849",
    "email_verified": false,
    "preferred_username": "admin"
}
Mathieu PASSENAUD