OIDC auth
Configure generic OIDC providers (Okta/Auth0/Azure AD/Keycloak, etc.) for a self-hosted server.
Happier can be configured with one or more OIDC provider instances. This is intended for enterprise/self-hosting deployments where GitHub isn’t the desired identity provider.
What standard is supported?
Happier’s “custom provider” support is OpenID Connect (OIDC) 1.0 using OAuth 2.0 Authorization Code Flow with PKCE.
- OIDC discovery is required (
/.well-known/openid-configurationunder yourissuer) - The provider must support code exchange at the token endpoint
id_tokenclaims are used as the primary identity profile; optional/userinfocan be enabled- Optional refresh tokens can be stored (encrypted) for offboarding re-checks
If you need SAML, the recommended approach is to use your IdP’s “OIDC app” or a SAML→OIDC bridge (Okta/Auth0/Azure AD/Keycloak, etc.), and configure Happier using the OIDC options below.
Config sources
You can configure providers via either:
AUTH_PROVIDERS_CONFIG_PATH(recommended): path to a JSON file on the serverAUTH_PROVIDERS_CONFIG_JSON: a JSON string (useful for simple deployments)
JSON schema (v1)
The config must be a JSON array. Each entry defines one provider instance:
[
{
"id": "okta",
"type": "oidc",
"displayName": "Acme Okta",
"issuer": "https://acme.okta.com/oauth2/default",
"clientId": "…",
"clientSecret": "…",
"redirectUrl": "https://YOUR_SERVER/v1/oauth/okta/callback",
"scopes": "openid profile email",
"httpTimeoutSeconds": 30,
"claims": {
"login": "preferred_username",
"email": "email",
"groups": "groups"
},
"allow": {
"usersAllowlist": ["alice", "bob"],
"emailDomains": ["example.com"],
"groupsAny": ["engineering", "platform"],
"groupsAll": ["employees"]
},
"fetchUserInfo": false,
"storeRefreshToken": false,
"ui": {
"buttonColor": "#111111",
"iconHint": "okta"
}
}
]Notes:
idbecomes the provider id used in policy (AUTH_SIGNUP_PROVIDERS=okta) and in the callback URL (/v1/oauth/:provider/callback).issuermust point at the provider’s OIDC issuer URL (discovery uses/.well-known/openid-configuration).- Make sure your OIDC app is configured to allow the exact
redirectUrl. scopesdefaults toopenid profile emailand must includeopenid.httpTimeoutSeconds(default30, clamp 1–120): timeout (seconds) for OIDC discovery and subsequent HTTP requests made by the OIDC client configuration.claimslets you map where to read the provider login/email/groups from (defaults shown above).allowrestricts eligibility (all comparisons are lowercased):usersAllowlist: matches against the provider login claim.emailDomains: allowsuser@domainonly ifdomainmatches.groupsAny: user must be in at least one group.groupsAll: user must be in all groups.
fetchUserInfo(defaultfalse): if enabled, the server fetches/userinfoand merges it into the identity profile.storeRefreshToken(defaultfalse): if enabled, the server stores an encrypted refresh token and uses refresh flows for periodic eligibility re-checks (offboarding) without requiring users to reconnect.uiprovides optional UI hints only (no security impact).
Group overage / external claims
Some providers (notably Microsoft Entra ID / Azure AD) may omit groups from tokens and instead return an “overage” pointer (e.g. _claim_names/_claim_sources). If you configure groupsAny/groupsAll, Happier will fail closed when it detects group overage (treating the user as ineligible) unless it can read groups from the configured claim source (for example by enabling fetchUserInfo and mapping claims.groups appropriately).
Enabling OIDC signup / login enforcement
Example: Okta-only signup + Okta required for ongoing access:
AUTH_ANONYMOUS_SIGNUP_ENABLED=false
AUTH_SIGNUP_PROVIDERS=okta
AUTH_REQUIRED_LOGIN_PROVIDERS=okta
AUTH_PROVIDERS_CONFIG_PATH=/etc/happier/auth-providers.jsonStep-by-step: add a new OIDC provider
- Pick a provider id (lowercase), e.g.
okta/auth0/entra. - In your IdP admin console, create an OIDC application:
- Grant type: Authorization Code
- Enable PKCE
- Add redirect URI:
https://YOUR_SERVER/v1/oauth/<providerId>/callback
- Put the provider config in
AUTH_PROVIDERS_CONFIG_PATH(preferred) orAUTH_PROVIDERS_CONFIG_JSON:- Set
issuer,clientId,clientSecret, andredirectUrlexactly (must match step 2).
- Set
- Enable it in policy:
- Allow signup via this provider:
AUTH_SIGNUP_PROVIDERS=<providerId> - Make it mandatory for ongoing access:
AUTH_REQUIRED_LOGIN_PROVIDERS=<providerId> - Disable anonymous signup if desired:
AUTH_ANONYMOUS_SIGNUP_ENABLED=false
- Allow signup via this provider:
- Make sure the client app can return from OAuth:
- Web (required unless you use
https://app.happier.dev): setHAPPIER_WEBAPP_URL(orHAPPIER_WEBAPP_OAUTH_RETURN_URL_BASE) - Mobile deep link: set
HAPPIER_WEBAPP_OAUTH_RETURN_URL_BASEand allow the scheme viaHAPPIER_OAUTH_RETURN_ALLOWED_SCHEMES(e.g.myapp)
- Web (required unless you use
- Validate:
- Restart the server (so it picks up env / config changes).
- Open the Happier app and confirm the new sign-in option appears on the welcome/login screen.
- If it doesn’t, double-check the redirect URL, issuer URL, and that
AUTH_SIGNUP_PROVIDERS/AUTH_REQUIRED_LOGIN_PROVIDERSreference the same provider id. (For troubleshooting, you can also inspectGET /v1/features.)
Note on “optional” web app URL env vars:
HAPPIER_WEBAPP_URL/HAPPIER_WEBAPP_OAUTH_RETURN_URL_BASEare only “optional” if you are using the hosted client athttps://app.happier.dev.- If you are self-hosting the web app, or using a local dev web UI, you must set one of these so the server can redirect back to your client after OAuth.
Troubleshooting:
- If you get redirected to
https://app.happier.deveven after settingHAPPIER_WEBAPP_URL, the server likely rejected your configured return URL as unsafe. For local web dev, usehttp://localhost:PORTorhttp://*.localhost:PORT(or usehttps://).
“Custom providers” beyond OIDC
At the moment, “custom providers” are supported via OIDC configuration (no plugin system for arbitrary protocols). If you need a non-OIDC provider, it must be implemented as a new provider module in the server and UI (similar to the built-in GitHub provider).