Applications (as IdP)
Integration Guides
Grafana

Grafana SSO with MojoAuth

Configure Grafana to authenticate users through MojoAuth using OpenID Connect (OIDC), via Grafana's Generic OAuth (generic_oauth) provider. MojoAuth acts as the OIDC provider and Grafana acts as the OIDC client — users sign in to Grafana with their MojoAuth-managed identity instead of a local Grafana password.

How it works

Grafana only supports the OIDC authorization code flow for generic_oauth. There is no IdP-initiated login for this provider — every sign-in starts from Grafana (SP-initiated).

Prerequisites

  • A MojoAuth project (test or live) with access to Developers → Applications.
  • Admin/server access to Grafana — either the ability to edit grafana.ini / set GF_AUTH_GENERIC_OAUTH_* environment variables and restart Grafana, or (on Grafana 10.3+) Administration → Authentication access to configure SSO from the UI.
  • Grafana OSS, Enterprise, or Cloud all support generic_oauth — no paid add-on is required for this provider itself (Grafana Enterprise adds team sync and enforced SSO settings, which are optional).
  • The externally reachable URL of your Grafana instance (its root_url), since the callback path is derived from it.

Step 1 — Create the MojoAuth OIDC application

Create a new OIDC application

In the MojoAuth dashboard, go to Developers → Applications → New Application → OIDC / OAuth 2.0. Give it a name (e.g. Grafana) and save.

Add Grafana's redirect URL

Before saving, add Grafana's callback URL to Allowed Callback URLs:

https://<grafana-host>/login/generic_oauth

Grafana always uses this exact path for generic_oauth — it is not configurable. If Grafana is served under a subpath (root_url ends in something other than /), the callback includes that subpath too, e.g. https://grafana.acme.com/grafana/login/generic_oauth — use the exact value Grafana will send (see Troubleshooting).

Copy the client credentials

Save the application and copy the Client ID and Client Secret — the secret is shown once. You'll use both in Step 2.

For background on OIDC applications, see OIDC Applications.

Step 2 — Configure Grafana

Grafana reads generic_oauth settings from grafana.ini, from GF_AUTH_GENERIC_OAUTH_* environment variables (which override the ini file), or — on newer Grafana versions — from the Administration → Authentication → Generic OAuth UI (stored in Grafana's database).

Set the provider config

Add (or edit) the [auth.generic_oauth] section in grafana.ini:

[auth.generic_oauth]
enabled = true
name = MojoAuth
allow_sign_up = true
client_id = {client_id}
client_secret = {client_secret}
scopes = openid email profile
auth_url = {BASE}/oauth/authorize
token_url = {BASE}/oauth/token
api_url = {BASE}/oauth/userinfo
use_pkce = true

Grafana's generic_oauth provider does not auto-discover endpoints from an OIDC discovery document — auth_url, token_url, and api_url must be set explicitly, as above, using MojoAuth's authorize, token, and userinfo endpoints. use_pkce = true enables PKCE on the authorization code exchange and is independent of discovery; MojoAuth supports PKCE, so leave it on.

Equivalent environment variables (useful for Docker/Kubernetes deployments), which take precedence over grafana.ini:

GF_AUTH_GENERIC_OAUTH_ENABLED=true
GF_AUTH_GENERIC_OAUTH_NAME=MojoAuth
GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP=true
GF_AUTH_GENERIC_OAUTH_CLIENT_ID={client_id}
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET={client_secret}
GF_AUTH_GENERIC_OAUTH_SCOPES="openid email profile"
GF_AUTH_GENERIC_OAUTH_AUTH_URL={BASE}/oauth/authorize
GF_AUTH_GENERIC_OAUTH_TOKEN_URL={BASE}/oauth/token
GF_AUTH_GENERIC_OAUTH_API_URL={BASE}/oauth/userinfo
GF_AUTH_GENERIC_OAUTH_USE_PKCE=true

Or configure it from the Grafana UI

On Grafana 10.3+, go to Administration → Authentication, add a Generic OAuth (or "OpenID Connect") provider, and fill in the same Client ID, Client secret, Auth URL, Token URL, API URL, and Scopes fields shown above. Settings saved this way are stored in Grafana's database and take precedence over grafana.ini/env vars unless your instance locks specific fields with configOverrides.

Restart Grafana

If you edited grafana.ini or environment variables, restart the Grafana server (or roll the deployment) for the new [auth.generic_oauth] section to take effect. UI-based SSO settings apply without a restart.

Step 3 — Confirm the redirect URL with MojoAuth

Grafana doesn't send back "SP metadata" the way a SAML app would — the only value MojoAuth needs is the callback URL you already added in Step 1:

https://<grafana-host>/login/generic_oauth

Double-check it's listed under the OIDC application's Allowed Callback URLs in the MojoAuth dashboard and matches Grafana's root_url scheme/host/subpath exactly — OIDC redirect URIs must match character-for-character.

Step 4 — Claim mapping and role sync

Grafana maps OIDC claims to user fields and, optionally, to a Grafana org role (Admin, Editor, Viewer) using JMESPath expressions evaluated against the ID token / userinfo claims.

Grafana settingPurposeExample
email_attribute_nameClaim to use as the user's email (default email)email
login_attribute_pathJMESPath for the Grafana login/usernamelogin or email
name_attribute_pathJMESPath for the display namename
role_attribute_pathJMESPath mapping a claim to Admin / Editor / Viewersee below
role_attribute_strictIf true, deny login when role_attribute_path resolves to nothingfalse
allow_assign_grafana_adminAllow the mapping to grant Grafana server admin, not just org adminfalse
allowed_domainsRestrict sign-in to email domainsacme.com
auto_assign_org_roleFallback org role when role_attribute_path is unset or emptyViewer

If you add a custom role claim to MojoAuth (via Custom Claims on the OIDC application) that emits admin, editor, or viewer per user, map it with:

role_attribute_path = contains(role, 'admin') && 'Admin' || contains(role, 'editor') && 'Editor' || 'Viewer'

Or, if MojoAuth emits the claim as a plain string rather than an array:

role_attribute_path = role == 'admin' && 'Admin' || role == 'editor' && 'Editor' || 'Viewer'

Example MojoAuth ID token payload this expression expects:

{
  "sub": "usr_9f2a1c",
  "email": "jane.doe@acme.com",
  "name": "Jane Doe",
  "role": "editor"
}

If you'd rather manage Grafana roles manually after the first login (instead of having MojoAuth's claim overwrite them on every sign-in), set skip_org_role_sync = true. This is common when only org membership/authentication should come from MojoAuth, and role assignment stays inside Grafana.

Step 5 — Test

Sign in via Grafana

Open Grafana's login page in an incognito/private window — you should see a "Sign in with MojoAuth" button (or whatever name you set in [auth.generic_oauth]). Click it.

Authenticate at MojoAuth

You're redirected to {BASE}/oauth/authorize, sign in with a MojoAuth-managed account, and are redirected back to https://<grafana-host>/login/generic_oauth.

Confirm success

A successful login lands you inside Grafana, signed in as that user, with the org role your role_attribute_path mapping resolved (or auto_assign_org_role if unset). Check Administration → Users to confirm the user was provisioned with the expected email, name, and role.

Troubleshooting

"login.OAuthLogin(generic_oauth) failed" in Grafana's logs

This is Grafana's generic wrapper error — the real cause is one line above it in the server log (invalid client secret, code exchange failure, userinfo call rejected, etc). Turn on debug logging for this provider to see the underlying reason:

[log]
filters = oauth.generic_oauth:debug

Then retry the login and re-check the logs.

redirect_uri mismatch / MojoAuth shows "invalid redirect_uri"

Grafana always redirects to <root_url>/login/generic_oauth. If Grafana's root_url in grafana.ini includes a subpath (e.g. https://host/grafana/), the actual redirect is https://host/grafana/login/generic_oauth — make sure that exact URL, including the subpath, is in the OIDC application's Allowed Callback URLs, not just the bare host.

Users always land as Viewer (role mapping isn't applying)

role_attribute_path silently falls back to auto_assign_org_role if the JMESPath expression errors or resolves to nothing. Decode the ID token (e.g. paste it at jwt.io) to confirm MojoAuth is actually sending the role claim, then test the JMESPath expression in isolation. Also check whether role_attribute_strict is blocking login instead of falling back, and whether skip_org_role_sync is set (which intentionally ignores the claim after first login).

Missing email or name after login

Usually caused by an incomplete scopes value. Grafana needs email and profile scopes in addition to openid to receive those claims from /oauth/userinfo — confirm scopes = openid email profile matches what's configured on the MojoAuth OIDC application, and that the corresponding claims aren't excluded by MojoAuth's custom claim rules.

TLS / certificate errors reaching MojoAuth's token or userinfo endpoint

If Grafana runs behind a corporate proxy or uses a custom CA bundle, the Grafana host's outbound HTTPS call to {BASE}/oauth/token or {BASE}/oauth/userinfo may fail cert validation. Ensure Grafana's host trusts the certificate chain MojoAuth serves; avoid disabling TLS verification outside of a throwaway test environment.

"It works for me but not for other users"

Check allowed_domains isn't scoped too narrowly, and that allow_sign_up = true is set if these are first-time Grafana logins — without it, Grafana will only let in users who already exist locally, and new MojoAuth-authenticated users will be rejected after a successful OIDC exchange.

Related