Happier Docs
Server

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-configuration under your issuer)
  • The provider must support code exchange at the token endpoint
  • id_token claims are used as the primary identity profile; optional /userinfo can 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 server
  • AUTH_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:

  • id becomes the provider id used in policy (AUTH_SIGNUP_PROVIDERS=okta) and in the callback URL (/v1/oauth/:provider/callback).
  • issuer must 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.
  • scopes defaults to openid profile email and must include openid.
  • httpTimeoutSeconds (default 30, clamp 1–120): timeout (seconds) for OIDC discovery and subsequent HTTP requests made by the OIDC client configuration.
  • claims lets you map where to read the provider login/email/groups from (defaults shown above).
  • allow restricts eligibility (all comparisons are lowercased):
    • usersAllowlist: matches against the provider login claim.
    • emailDomains: allows user@domain only if domain matches.
    • groupsAny: user must be in at least one group.
    • groupsAll: user must be in all groups.
  • fetchUserInfo (default false): if enabled, the server fetches /userinfo and merges it into the identity profile.
  • storeRefreshToken (default false): if enabled, the server stores an encrypted refresh token and uses refresh flows for periodic eligibility re-checks (offboarding) without requiring users to reconnect.
  • ui provides 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.json

Step-by-step: add a new OIDC provider

  1. Pick a provider id (lowercase), e.g. okta / auth0 / entra.
  2. 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
  3. Put the provider config in AUTH_PROVIDERS_CONFIG_PATH (preferred) or AUTH_PROVIDERS_CONFIG_JSON:
    • Set issuer, clientId, clientSecret, and redirectUrl exactly (must match step 2).
  4. 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
  5. Make sure the client app can return from OAuth:
    • Web (required unless you use https://app.happier.dev): set HAPPIER_WEBAPP_URL (or HAPPIER_WEBAPP_OAUTH_RETURN_URL_BASE)
    • Mobile deep link: set HAPPIER_WEBAPP_OAUTH_RETURN_URL_BASE and allow the scheme via HAPPIER_OAUTH_RETURN_ALLOWED_SCHEMES (e.g. myapp)
  6. 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_PROVIDERS reference the same provider id. (For troubleshooting, you can also inspect GET /v1/features.)

Note on “optional” web app URL env vars:

  • HAPPIER_WEBAPP_URL / HAPPIER_WEBAPP_OAUTH_RETURN_URL_BASE are only “optional” if you are using the hosted client at https://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.dev even after setting HAPPIER_WEBAPP_URL, the server likely rejected your configured return URL as unsafe. For local web dev, use http://localhost:PORT or http://*.localhost:PORT (or use https://).

“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).

On this page