Testing environment

This blog post will show you how to integrate Grafana (7.3.7) and Keycloak (12.0.2) to achieve a single sign-on scenario (including a proper log-out) by using the OAuth/OpenID Connect protocol. It also provides a roles-based approach, so that Grafana is able to apply permissions based on the role of the logged-in user (Admin, Editor, Viewer).

To avoid issues with resolving host addresses in different containers, I used a local Grafana installation based on Homebrew. As usual, testing was done on macOS.

Prepare Keycloak

Create and configure the Grafana client

In your Keycloak realm create a new client: Clients / Create.

Client ID: grafana

Client: Protocol: openid-connect

Root URL: http://localhost:3000

Save

* * *

Adjust the configuration:

Access type: confidential

Root URL: http://localhost:3000

Valid Redirect URIs: http://localhost:3000/*

(Change this URL for a productive installation to make it more secure; at the moment we use the wildcard to avoid typos, …).

Clear the other URLs, we don’t need them currently.

Save

* * *

By changing the access type to confidential, we received a secret to be used in combination with our client.

Navigate to the Credentials tab, copy the value for Secret and store it for later use.

* * *

Let’s create a role mapper for providing user role information in the token payload.

Navigate to the Mappers tab, Create a new Mapper with the values:

Grafana role mapper.

Name: Roles

Mapper Type: User Client Role

Client ID: grafana

Token Claim Name: roles

Claim JSON type: String

* * *

As we want to have different types of user roles in Grafana, switch to the Roles tab.

Add the following roles:

  • admin
  • editor
  • viewer

Keycloak roles for Grafana

* * *

Clients: grafana: Scope tab

Full Scope Allowed: Off

This reduces the amount of data shared in the JWT token.

* * *

For the first test, assign the admin role to the user you want to login with into Grafana later:

Users: Select user | Add user: Tab Role Mappings: Client Roles: grafana: Add admin

Client role assigned to the user.

Test the Grafana client

You can test if an access token is provided by Keycloak by using a curl command, adjust the parameters as needed.

curl -s \
-d "client_id=grafana" \
-d "client_secret=replace-with-your-client-secret" \
-d "username=replace-with-keycloak-user-name-with-later-access-to-grafana" \
-d "password=replace-with-keycloak-user-password-with-later-access-to-grafana" \
-d "grant_type=password" \
"http://localhost:8080/auth/realms/replace-with-your-realm/protocol/openid-connect/token"

If you receive an error like

{"error":"invalid_grant","error_description":"Invalid user credentials"}

you might need to adjust the settings for the Direct Grant authentication flow in Keycloak:

Authentication: Flows tab: Direct Grant

Modify the Direct Grant Flow

Set the radio button for Direct Grant - Conditional OTP to ALTERNATIVE OR DISABLED during the test.

Try to test again with the curl command and ideally you should receive a token value.

{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIg ....

If it does not work, verify your parameters. If you still do not receive a token, please ask your friend Google …

You can inspect the data provided in “access_token” with tools like https://jwt.io/ or https://jwt.ms/. In the payload, you should also find the roles array and the name of the assigned role (admin).

You can find an excellent article about Keycloak and Grafana and especially how to validate a JWT token on Janik’s blog.

Don’t forget to turn back the setting for the Direct Grant flow if working with a productive instance!

Configure your Grafana instance

Install with Homebrew

Check the article on how to install Grafana on macOS with Homebrew, if you don’t already have it installed.

In short:

# install Grafana
brew update
brew install grafana
# upgrade
brew update
brew reinstall grafana
# start service
brew services start grafana
# http://localhost:3000
brew services stop grafana

This installs Grafana to /usr/local/Cellar/grafana/.

The default credentials are admin/admin, the log file is /usr/local/var/log/grafana/grafana.log.

Add configuration for Keycloak

Hint: The OpenID Connect protocol requires providing a standard URL to lookup configuration values. The URL looks like this:

http(s)://<keycloak-server-URL>/auth/realms/<realm-name>/.well-known/openid-configuration

Open this URL in a browser to find values for authorization_endpoint, token_endpoint, userinfo_endpoint, and end_session_endpoint (see below).

Note: If you read about adjusting the Grafana configuration, there is often the instruction to add a custom.ini file. This seems to be true only if you download or build the source of the Grafana package yourself. When using a tool like Homebrew, the file you need to adjust is grafana.ini.

Open the file /usr/local/etc/grafana/grafana.ini in your preferred editor.

Find the section [auth.generic_oauth] and modify it like below:

[auth.generic_oauth]
name = Login Keycloak (local)
enabled = true
allow_sign_up = true
client_id = grafana
client_secret = <replace-with-your-client-secret>
scopes = openid profile email
email_attribute_name = email:primary
role_attribute_path = "contains(roles[*], 'admin') && 'Admin' || contains(roles[*], 'editor') && 'Editor' || 'Viewer'"
auth_url = http://localhost:8080/auth/realms/<replace-realm>>/protocol/openid-connect/auth
token_url = http://localhost:8080/auth/realms/<replace-realm>>/protocol/openid-connect/token
api_url = http://localhost:8080/auth/realms/<replace-realm>>/protocol/openid-connect/userinfo

Adjust the values as needed like the Keycloak URL, realm, and client id.

If the Grafana service was already running, stop it and start the service again.

Test Keycloak integration

Open the Grafana interface in the browser, http://localhost:3000. You should see the option for using Keycloak on the login screen. If not, it’s likely you edited the wrong configuration file and settings have not been picked up.

Grafana Keycloak log-in option.

Click the button and log-in with Keycloak. If everything is OK you should be logged-in with your Keycloak users and the role “Admin”. You can check this in your user preferences:

Grafana Admin role log-in.

Test log-out in Grafana

We managed to log-ing to Grafana in an SSO-like fashion and even use roles within Grafana!

Please test what happens when using the “Sign out” menu item in Grafana. Looks good, because you see the log-in screen again?

Click on the Sign in with Keycloak button again: No need to enter your credentials, the session in Keycloak and the browser cookie are still there. That means, you signed out of Grafana but not from the central SSO service, therefore you don’t need to provide any credentials again (that all happens transparently in the background).

Configure log-out with Keycloak

Stop the Grafana service, open /usr/local/etc/grafana/grafana.ini, find the section [auth]. Provide the value for signout_redirect_url. You can use the value for end_session_endpoint found with the “well-known” URL above.

[auth]
signout_redirect_url = http://localhost:8080/auth/realms/<replace-realm>/protocol/openid-connect/logout

Make sure to clean the browser session, start the Grafana service, and log in to Grafana with Keycloak.

Again, use the Sign-out link in Grafana. You are logged out of Grafana and Keycloak, so your session has been ended. You can test this by opening http://localhost:3000/login and clicking on “Keycloak” again - this time providing credentials again should be required.

What is not nice is that you are shown a blank page after logout (… protocol/openid-connect/logout): Let’s fix this.

Stop Grafana, open grafana.ini. We will add a redirect_uri parameter to the signout URL.

[auth]
# unencoded:
# signout_redirect_url = http://localhost:8180/auth/realms/magnolia_admincentral/protocol/openid-connect/logout?redirect_uri=http://localhost:3000/login
#
signout_redirect_url = http://localhost:8180/auth/realms/magnolia_admincentral/protocol/openid-connect/logout?redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Flogin

Above we appended ?redirect_uri=http://localhost:3000/login to the signout_redirect_url. We just need to enter the parameter in encoded format. You can use a service for proper encoding, for example, URL Encoder / Decoder.

For the last time, start the Grafana service and test log-in and log-out with Keycloak again. The nice thing about the redirect_uri parameter is that this can be any URL you want to redirect to after logging out, it does not have to be Grafana.

Hopefully, everything works like a charm now …

More information and tools