Grafana OAuth SSO Integration with KeyCloak

Single Sign-On integration is important. In my previous post, I demonstrated how to use Keycloak as the authentication layer in a FastAPI application. Now we will use Keycloak as identity provider for Grafana.

I'm going to run all those in my local env. So change the hostnames or FQDN for your domain.

Create KeyCloak Client

Properties of Keycloak client must be like following;

  • Client Type: OpenID Connect
    Client ID: grafana-oauth
  • Authentication: On
    Authentication Flow: Standart Flow Enabled
    Direct access grants Enabled
  • Root URL: Grafana's root url
    Home URL: Grafana's root url
    Valid Redirect URIs: Grafana's root url + /login/generic_oauth
    Web Origins: Grafana's root url

After creating the client, go to client details page and click Credentials tab to obtain client secret.

Grafana Compose File and OAuth Configuration

What to replace the file in below;

  • Your realm name and Client secret
  • Your keycloak hostname. (There are two domains. Localhost is sent to browser. Host.docker.internal is for Grafana access to Keycloak.
version: '3.8'

services:
  grafana:
    image: docker.io/grafana/grafana-oss:12.0.2
    container_name: grafana
    restart: unless-stopped
    environment:
    - GF_SERVER_ROOT_URL=http://localhost:3000/
    - GF_PLUGINS_PREINSTALL=grafana-clock-panel
    - GF_SECURITY_ADMIN_USER=admin
    - GF_SECURITY_ADMIN_PASSWORD=admin
    - GF_AUTH_GENERIC_OAUTH_ENABLED=true
    - GF_AUTH_GENERIC_OAUTH_NAME=Keycloak-OAuth
    - GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP=true
    - GF_AUTH_GENERIC_OAUTH_CLIENT_ID=grafana-oauth
    - GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET=[SECRET]
    - GF_AUTH_GENERIC_OAUTH_SCOPES=openid email profile offline_access roles
    - GF_AUTH_GENERIC_OAUTH_EMAIL_ATTRIBUTE_PATH=email
    - GF_AUTH_GENERIC_OAUTH_LOGIN_ATTRIBUTE_PATH=username
    - GF_AUTH_GENERIC_OAUTH_NAME_ATTRIBUTE_PATH=full_name
    - GF_AUTH_GENERIC_OAUTH_AUTH_URL=http://localhost:8080/realms/local/protocol/openid-connect/auth
    - GF_AUTH_GENERIC_OAUTH_TOKEN_URL=http://host.docker.internal:8080/realms/local/protocol/openid-connect/token
    - GF_AUTH_GENERIC_OAUTH_API_URL=http://host.docker.internal:8080/realms/local/protocol/openid-connect/userinfo
    - GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH=contains(roles[*], 'admin') && 'Admin' || contains(roles[*], 'editor') && 'Editor' || 'Viewer'

    ports:
     - '3000:3000'
    volumes:
     - 'grafana_storage:/var/lib/grafana'
volumes:
  grafana_storage: 

You would see you can log in to Grafana via your Keycloak user. One important note here. In the localhost; you can't map Keycloak roles to Grafana users. OAUTH_ROLE_ATTRIBUTE_PATH defines mapping. So normally you should assign that role to user. It's happening due to localhost and host.docker.internal domains' differences. The JWT token couldn't be verified by Grafana so it doesn't fetch it. But it works in production. And make sure, the path matches with the key in your JWT token. Adjust it by the token. Or modify client scope details in Keycloak.