3rd-party app SSO
Portainer, Grafana, Argo CD, Proxmox, Gitea — drop WolfieAuth in front of any app that speaks OIDC or OAuth2. Step-by-step recipes.
3rd-party app SSO — using WolfieAuth as the identity provider
TL;DR: WolfieAuth is a standard OIDC provider at
https://auth.wolfieguard.com. Anything that speaks OIDC or generic OAuth2 (Portainer, Grafana, Argo CD, Proxmox, Gitea, Nextcloud, …) plugs in by registering one OidcClient and pasting four URLs into the app’s auth settings. Passwordless propagates automatically — once the user signs in to WolfieAuth with a passkey or magic link, downstream apps just see a validid_token; they never know how the user authenticated.
The three things you always do
Every integration on this page follows the same three steps:
- Register the app in WolfieAuth.
https://auth.wolfieguard.com/admin/clients/new→ pickappKind=oauth(orcustom), set the redirect URI to whatever the app’s docs say (we list them below), copy the resultingclient_idandclient_secret. - Paste the discovery URL into the app. Modern apps just want
https://auth.wolfieguard.com/.well-known/openid-configurationand they auto-discover the rest. Older apps want the four endpoints by hand:- Authorize:
https://auth.wolfieguard.com/auth - Token:
https://auth.wolfieguard.com/token - Userinfo:
https://auth.wolfieguard.com/me - JWKS:
https://auth.wolfieguard.com/jwks
- Authorize:
- Test the round-trip — log out, click “Sign in with WolfieAuth,” confirm you land back authenticated. If you have a passkey on your WolfieAuth account, this entire flow is passwordless end-to-end.
The rest of the page is per-app boilerplate: where each setting lives, what scopes to request, and which claims to map to roles.
Portainer
Portainer ships with both Community Edition (free, “Custom OAuth” provider) and Business Edition (native OIDC dropdown). Both work. BE is more turn-key because it auto-discovers via the .well-known URL.
Portainer CE — Custom OAuth flow
In Portainer admin: Settings → Authentication → OAuth → Custom.
| Field | Value |
|---|---|
| Client ID | <from-wolfieauth-panel> |
| Client secret | <from-wolfieauth-panel> |
| Authorization URL | https://auth.wolfieguard.com/auth |
| Access token URL | https://auth.wolfieguard.com/token |
| Resource URL (userinfo) | https://auth.wolfieguard.com/me |
| Redirect URL | https://portainer.your-host.tld/ |
| Logout URL | https://auth.wolfieguard.com/session/end |
| User identifier | email (or sub for stable IDs) |
| Scopes | openid email profile |
Then in WolfieAuth /admin/clients/<your-portainer-app> → Overview, register the Redirect URI as https://portainer.your-host.tld/. Save. Click “Sign in with OAuth” on Portainer’s login page — you should bounce to auth.wolfieguard.com, sign in (or pass through silently if you already have an SSO cookie), and land back as a Portainer user.
Portainer BE — native OIDC
Settings → Authentication → OIDC.
| Field | Value |
|---|---|
| Provider | Custom |
| Client ID / secret | <from-wolfieauth-panel> |
| Authorization URL | https://auth.wolfieguard.com/auth |
| Access token URL | https://auth.wolfieguard.com/token |
| Resource URL | https://auth.wolfieguard.com/me |
| Redirect URL | auto-filled by Portainer |
| Logout URL | https://auth.wolfieguard.com/session/end |
| Scopes | openid email profile |
| User identifier | email |
BE adds team auto-mapping: if you tick “Auto team membership” and pick a default team, every user that signs in via WolfieAuth gets auto-added there. You can override per-user later.
Mapping WolfieAuth roles to Portainer
Portainer doesn’t read JWT claims for roles by default — every OIDC user lands as a “standard user.” Promote them to admin by either:
- Setting
is_adminonce via Portainer’s Users page, OR - Pre-creating a “wolfieauth-admins” team in Portainer and toggling Auto team membership with that team selected.
For finer-grained gating per WolfieAuth org or plan, use a JWT template on the OidcClient to remap wolfieauth_role_slug to a groups: ["admin"] claim, then enable Portainer BE’s group sync.
Grafana
Grafana has first-class Generic OAuth support that maps cleanly to WolfieAuth.
grafana.ini (or env vars):
[auth.generic_oauth]
enabled = true
name = WolfieAuth
client_id = <from-wolfieauth-panel>
client_secret = <from-wolfieauth-panel>
scopes = openid email profile
auth_url = https://auth.wolfieguard.com/auth
token_url = https://auth.wolfieguard.com/token
api_url = https://auth.wolfieguard.com/me
allow_sign_up = true
role_attribute_path = contains(wolfieauth_role_slug, 'admin') && 'Admin' || contains(wolfieauth_role_slug, 'editor') && 'Editor' || 'Viewer'
In WolfieAuth, register the redirect URI as https://grafana.your-host.tld/login/generic_oauth. The role_attribute_path JMESPath expression maps your WolfieAuth role slug to Grafana’s three roles.
For Grafana org / team mapping, request the org scope in WolfieAuth and use:
team_ids_attribute_path = wolfieauth_org_slug
Argo CD
Argo CD’s OIDC config lives in the argocd-cm ConfigMap:
data:
url: https://argocd.your-host.tld
oidc.config: |
name: WolfieAuth
issuer: https://auth.wolfieguard.com
clientID: <from-wolfieauth-panel>
clientSecret: $oidc.wolfieauth.clientSecret # from secret
requestedScopes: ["openid", "profile", "email"]
requestedIDTokenClaims:
groups:
essential: true
In WolfieAuth: redirect URI = https://argocd.your-host.tld/auth/callback. Use a JWT template to emit groups: ["{{wolfieauth_role_slug}}"] so Argo’s RBAC policies can match against it.
argocd-rbac-cm:
data:
policy.csv: |
g, admin, role:admin
g, editor, role:readonly
Proxmox VE 8+
Proxmox 8 added native OIDC. Datacenter → Permissions → Realms → Add → OpenID Connect.
| Field | Value |
|---|---|
| Realm | wolfieauth |
| Issuer URL | https://auth.wolfieguard.com |
| Client ID / Key | <from-wolfieauth-panel> |
| Default | tick if this should be the login default |
| Username Claim | email |
| Scopes | openid email profile |
| Autocreate users | tick |
Redirect URI to register in WolfieAuth: https://proxmox.your-host.tld:8006/. Proxmox auto-creates users on first login as <email>@wolfieauth. Assign permissions in Datacenter → Permissions → Add → User Permission.
Gitea / Forgejo
Site Administration → Authentication Sources → Add → OAuth2 → OpenID Connect.
| Field | Value |
|---|---|
| Authentication Name | WolfieAuth |
| OAuth2 Provider | OpenID Connect |
| Client ID | <from-wolfieauth-panel> |
| Client Secret | <from-wolfieauth-panel> |
| OpenID Connect Auto Discovery URL | https://auth.wolfieguard.com/.well-known/openid-configuration |
| Custom Icon URL | https://wolfieguard.com/favicon.ico |
| Required claim name / value | wolfieauth_membership_approval / APPROVED (optional gate) |
Redirect URI: https://gitea.your-host.tld/user/oauth2/WolfieAuth/callback.
Nextcloud
Install the OpenID Connect Login app, then Settings → Administration → OpenID Connect Login:
Identifier: WolfieAuth
Authorization URL: https://auth.wolfieguard.com/auth
Token URL: https://auth.wolfieguard.com/token
Userinfo URL: https://auth.wolfieguard.com/me
Logout URL: https://auth.wolfieguard.com/session/end
JWKS URL: https://auth.wolfieguard.com/jwks
Client ID / Secret: <from-wolfieauth-panel>
Scopes: openid email profile
Attribute mapping → uid: sub
→ display name: name
→ email: email
Redirect URI: https://nextcloud.your-host.tld/apps/oidc_login/oidc.
Apps without native OIDC — oauth2-proxy / Traefik forward-auth
For apps that don’t speak OIDC at all (admin dashboards, internal Kibana, static dashboards, legacy PHP panels), put oauth2-proxy or Traefik’s forward-auth middleware between the app and the world.
oauth2-proxy (docker-compose snippet)
services:
oauth2-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:latest
command:
- --provider=oidc
- --oidc-issuer-url=https://auth.wolfieguard.com
- --client-id=<from-wolfieauth-panel>
- --client-secret=<from-wolfieauth-panel>
- --redirect-url=https://protected.your-host.tld/oauth2/callback
- --upstream=http://your-internal-app:8080
- --cookie-secret=$(openssl rand -base64 32)
- --email-domain=*
- --pass-access-token=true
- --set-xauthrequest=true
ports: ["4180:4180"]
Now https://protected.your-host.tld is gated by WolfieAuth — no patches to the upstream app needed. Headers X-Auth-Request-User, X-Auth-Request-Email, X-Auth-Request-Groups reach your app so it can identify the user.
Traefik forward-auth
http:
middlewares:
wolfieauth-sso:
forwardAuth:
address: "http://oauth2-proxy:4180/oauth2/auth"
trustForwardHeader: true
authResponseHeaders:
- X-Auth-Request-User
- X-Auth-Request-Email
Attach to any router: traefik.http.routers.kibana.middlewares=wolfieauth-sso@file.
Other apps that work the same way
The pattern is the same as everything above — register a client, paste four URLs, optionally remap a claim. Sample list of stacks confirmed against WolfieAuth’s OIDC endpoints:
| Category | App | OIDC docs section to find |
|---|---|---|
| DevOps | GitLab CE, Jenkins, Rancher, Harbor, Drone, Woodpecker, Sentry, Vault | “OAuth provider” / “OIDC” / “Generic OIDC” |
| Self-hosted | Outline, Mattermost, Wiki.js, BookStack, Zammad, Vaultwarden (via SSO Bridge) | “SSO” / “Authentication providers” |
| Infra | MinIO, Kibana / OpenSearch (via openid plugin), Authelia (as upstream IdP) | “Identity provider” |
| Monitoring | Prometheus + Alertmanager (via oauth2-proxy), Loki dashboards (inherit Grafana) | n/a — proxied |
Troubleshooting
“redirect_uri_mismatch” — the URI you registered in WolfieAuth doesn’t byte-match what the app sends. Trailing slashes, http vs https, and trailing /callback paths all matter. Copy the URL straight from the app’s network tab and paste it verbatim.
“invalid_client” — client_secret mismatch. Rotate it via /admin/clients/<id> → Rotate Secret, paste the new one into the app, save, retry.
“User has no role” / lands as guest — your role claim isn’t reaching the app under the name it expects. Check the app’s docs for the expected attribute (Grafana wants role, Portainer reads is_admin, Argo CD wants groups). Use a JWT template on the OidcClient to rename or compute the claim. Preview at /admin/clients/<id>/jwt-template/preview shows what the rendered token will look like.
Nothing happens on click — check https://auth.wolfieguard.com/.well-known/openid-configuration resolves from inside the app’s network. Self-hosted apps in private networks sometimes can’t reach the public IdP — open egress for auth.wolfieguard.com:443 first.
Logout doesn’t really log out — the app cleared its local cookie but the SSO cookie at auth.wolfieguard.com stayed alive. Configure the app’s “End-session” / “Logout URL” to https://auth.wolfieguard.com/session/end?id_token_hint=<id_token>&post_logout_redirect_uri=<your-app-url> so RP-initiated logout fires.
Continue reading
- SSO & Sessions — what’s actually on the wire during the OIDC dance
- Admin — JWT templates, redirect URIs, secret rotation
- Reseller mode — when your downstream app needs to itself host sub-tenants
Last updated: