Grafana
This guide walks you through connecting Grafana to Nauthera so that users can sign in with their Nauthera account and have Grafana roles assigned automatically based on group membership.
What you will set up
- OIDC sign-in for Grafana via Nauthera
- Group-to-role mapping (e.g.
grafana-adminsgroup becomes GrafanaAdmin) - Optional: restrict access to specific groups
Prerequisites
- A running Nauthera instance with a reachable issuer URL (e.g.
https://auth.example.com) - Grafana 9.0+ deployed in the same cluster or reachable from Nauthera
- A
ClusterAuthPolicyorAuthPolicythat includes thegroupsscope
Step 1 — Create the OidcClient
Create an OidcClient for Grafana. The operator will provision a Secret with the generated client_id and client_secret.
apiVersion: auth.nauthera.io/v1alpha1
kind: OidcClient
metadata:
name: grafana
namespace: monitoring
spec:
displayName: Grafana
redirectUris:
- "https://grafana.example.com/login/generic_oauth"
allowedScopes:
- openid
- profile
- email
- groups
grantTypes:
- authorization_code
- refresh_tokenApply the resource:
kubectl apply -f grafana-oidc-client.yamlVerify the credentials Secret was created:
kubectl get secret grafana-credentials -n monitoring -o jsonpath='{.data.client_id}' | base64 -dStep 2 — Enable the groups scope
Make sure the groups scope is allowed in your policy. If you already have a ClusterAuthPolicy, add groups to the scopes list:
apiVersion: auth.nauthera.io/v1alpha1
kind: ClusterAuthPolicy
metadata:
name: default
spec:
scopes:
- openid
- profile
- email
- groups
claimMappings:
- claim: groups
attribute: groupsThis ensures the groups claim is included in the ID token when Grafana requests the groups scope.
Step 3 — Create groups and assign users
Create the groups that Grafana will use for role mapping:
# Create groups
kubectl exec -n nauthera-system deploy/nauthera-server -- \
nauthera admin group create grafana-admins
kubectl exec -n nauthera-system deploy/nauthera-server -- \
nauthera admin group create grafana-editors
kubectl exec -n nauthera-system deploy/nauthera-server -- \
nauthera admin group create grafana-viewers
# Assign users to groups
kubectl exec -n nauthera-system deploy/nauthera-server -- \
nauthera admin group add-user grafana-admins alice
kubectl exec -n nauthera-system deploy/nauthera-server -- \
nauthera admin group add-user grafana-editors bobIf you use SCIM provisioning, groups are synced automatically from your directory (Okta, Entra ID, etc.).
Step 4 — Configure Grafana
Option A: Environment variables
Mount the Nauthera credentials Secret and configure Grafana via environment variables. This is the simplest approach for Kubernetes deployments.
apiVersion: apps/v1
kind: Deployment
metadata:
name: grafana
namespace: monitoring
spec:
template:
spec:
containers:
- name: grafana
image: grafana/grafana:11.6.0
env:
# --- OIDC client credentials from Nauthera ---
- name: OIDC_CLIENT_ID
valueFrom:
secretKeyRef:
name: grafana-credentials
key: client_id
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: grafana-credentials
key: client_secret
# --- Generic OAuth configuration ---
- name: GF_AUTH_GENERIC_OAUTH_ENABLED
value: "true"
- name: GF_AUTH_GENERIC_OAUTH_NAME
value: "Nauthera"
- name: GF_AUTH_GENERIC_OAUTH_CLIENT_ID
value: "$(OIDC_CLIENT_ID)"
- name: GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET
value: "$(OIDC_CLIENT_SECRET)"
- name: GF_AUTH_GENERIC_OAUTH_SCOPES
value: "openid profile email groups"
- name: GF_AUTH_GENERIC_OAUTH_AUTH_URL
value: "https://auth.example.com/oauth2/authorize"
- name: GF_AUTH_GENERIC_OAUTH_TOKEN_URL
value: "https://auth.example.com/oauth2/token"
- name: GF_AUTH_GENERIC_OAUTH_API_URL
value: "https://auth.example.com/oauth2/userinfo"
- name: GF_AUTH_GENERIC_OAUTH_USE_PKCE
value: "true"
# --- Role mapping via groups claim ---
- name: GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH
value: "contains(groups[*], 'grafana-admins') && 'Admin' || contains(groups[*], 'grafana-editors') && 'Editor' || 'Viewer'"
- name: GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_STRICT
value: "true"
# --- Auto sign-up and sync ---
- name: GF_AUTH_GENERIC_OAUTH_AUTO_LOGIN
value: "false"
- name: GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP
value: "true"
- name: GF_AUTH_GENERIC_OAUTH_ALLOW_ASSIGN_GRAFANA_ADMIN
value: "true"
# --- Optional: use Grafana's group sync for Org roles ---
- name: GF_AUTH_GENERIC_OAUTH_GROUPS_ATTRIBUTE_PATH
value: "groups"
- name: GF_SERVER_ROOT_URL
value: "https://grafana.example.com"Option B: grafana.ini
If you use a ConfigMap or grafana.ini directly:
[auth.generic_oauth]
enabled = true
name = Nauthera
client_id = <from grafana-credentials Secret>
client_secret = <from grafana-credentials Secret>
scopes = openid profile email groups
auth_url = https://auth.example.com/oauth2/authorize
token_url = https://auth.example.com/oauth2/token
api_url = https://auth.example.com/oauth2/userinfo
use_pkce = true
allow_sign_up = true
allow_assign_grafana_admin = true
role_attribute_path = contains(groups[*], 'grafana-admins') && 'Admin' || contains(groups[*], 'grafana-editors') && 'Editor' || 'Viewer'
role_attribute_strict = true
groups_attribute_path = groupsOption C: Helm values (grafana/grafana chart)
# values.yaml
grafana.ini:
auth.generic_oauth:
enabled: true
name: Nauthera
scopes: openid profile email groups
auth_url: https://auth.example.com/oauth2/authorize
token_url: https://auth.example.com/oauth2/token
api_url: https://auth.example.com/oauth2/userinfo
use_pkce: true
allow_sign_up: true
allow_assign_grafana_admin: true
role_attribute_path: >-
contains(groups[*], 'grafana-admins') && 'Admin'
|| contains(groups[*], 'grafana-editors') && 'Editor'
|| 'Viewer'
role_attribute_strict: true
groups_attribute_path: groups
envFromSecrets:
- grafana-credentials
envValueFrom:
GF_AUTH_GENERIC_OAUTH_CLIENT_ID:
secretKeyRef:
name: grafana-credentials
key: client_id
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET:
secretKeyRef:
name: grafana-credentials
key: client_secretStep 5 — Verify
- Open Grafana and click Sign in with Nauthera.
- Authenticate at the Nauthera login page.
- After redirect, check your Grafana profile — your email, name, and role should be populated.
- Verify role assignment: a user in the
grafana-adminsgroup should see the Admin settings gear icon.
Role mapping reference
The role_attribute_path uses JMESPath expressions evaluated against the ID token claims. Here are common patterns:
| Expression | Result |
|---|---|
contains(groups[*], 'grafana-admins') && 'GrafanaAdmin' | Grafana Server Admin if in group |
contains(groups[*], 'grafana-admins') && 'Admin' || 'Viewer' | Org Admin or fallback to Viewer |
contains(groups[*], 'grafana-admins') && 'Admin' || contains(groups[*], 'grafana-editors') && 'Editor' || 'Viewer' | Three-tier mapping |
Set role_attribute_strict: true to deny access if the expression returns no valid role.
Restricting access to specific groups
To only allow certain groups to sign in, add requiredGroups to the OidcClient:
spec:
requiredGroups:
- grafana-admins
- grafana-editors
- grafana-viewersUsers not in any of these groups will see an access denied error at login time.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| "User not found" after login | allow_sign_up is false | Set GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP=true |
| Role is always Viewer | groups scope not requested or not in policy | Add groups to OidcClient allowedScopes and policy scopes |
| Groups claim missing from token | No claimMappings in policy | Add claimMappings with claim: groups, attribute: groups |
| Redirect URI mismatch | Grafana callback URL does not match redirectUris | Ensure the redirect URI ends with /login/generic_oauth |
| PKCE error | Grafana or Nauthera PKCE mismatch | Set use_pkce = true in Grafana config |
Related
- OidcClient — Full CRD reference
- AuthPolicy — Scope and claim mapping configuration
- User Management — Creating users and groups
- SCIM 2.0 — Automatic group sync from your directory