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/ setGF_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_oauthGrafana 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 = trueGrafana'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=trueOr 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_oauthDouble-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 setting | Purpose | Example |
|---|---|---|
email_attribute_name | Claim to use as the user's email (default email) | email |
login_attribute_path | JMESPath for the Grafana login/username | login or email |
name_attribute_path | JMESPath for the display name | name |
role_attribute_path | JMESPath mapping a claim to Admin / Editor / Viewer | see below |
role_attribute_strict | If true, deny login when role_attribute_path resolves to nothing | false |
allow_assign_grafana_admin | Allow the mapping to grant Grafana server admin, not just org admin | false |
allowed_domains | Restrict sign-in to email domains | acme.com |
auto_assign_org_role | Fallback org role when role_attribute_path is unset or empty | Viewer |
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:debugThen 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.