# Configure an OIDC provider

Source: https://docs.settlemint.com/docs/developers/sso-oidc/configure-provider
Reference for every auth.oidcProviders field, its environment variable, default, and the claim contract any OIDC identity provider must satisfy for DALP sign-in.



DALP configures OIDC sign-in through the `auth.oidcProviders` list in `config.yml`. The list is provider-neutral: each entry describes one OIDC connection, and any standards-compliant issuer works without provider-specific code. Use this page as the field-by-field reference; for a concrete walkthrough see [FusionAuth setup](/docs/developers/sso-oidc/fusionauth-setup).

## Configuration shape [#configuration-shape]

```yaml
auth:
  oidcProviders:
    - id: ${OIDC_PROVIDER_ID:-}
      displayName: ${OIDC_PROVIDER_DISPLAY_NAME:-}
      issuer: ${OIDC_PROVIDER_ISSUER:-}
      clientId: ${OIDC_PROVIDER_CLIENT_ID:-}
      clientSecret: ${OIDC_PROVIDER_CLIENT_SECRET:-}
      adminClaim: ${OIDC_PROVIDER_ADMIN_CLAIM:-}
      # scopes: optional; defaults to openid email profile
      # requireIssuerValidation: optional; defaults to true
      # apiKey + applicationId: optional; enable the OIDC_MFA wallet-signing method
      apiKey: ${OIDC_PROVIDER_MFA_API_KEY:-}
      applicationId: ${OIDC_PROVIDER_MFA_APPLICATION_ID:-}
```

The `${VAR:-default}` syntax reads an environment variable and falls back to the value after `:-` when the variable is unset or empty. This lets a single committed `config.yml` carry safe defaults while deployments inject real values through the environment. See [Deploy OIDC in production](/docs/developers/sso-oidc/deploy-production) for the Helm and secret-handling model.

## Field reference [#field-reference]

| Field                     | Environment variable                      | Type      | Default                        | Sensitive | Purpose                                                                                                                                                                                    |
| ------------------------- | ----------------------------------------- | --------- | ------------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id`                      | `OIDC_PROVIDER_ID`                        | string    | `""`                           | No        | Stable provider identifier. Used as the sign-in button key and in the callback URL path.                                                                                                   |
| `displayName`             | `OIDC_PROVIDER_DISPLAY_NAME`              | string    | `""`                           | No        | Label shown on the sign-in button. Falls back to `id` when empty.                                                                                                                          |
| `issuer`                  | `OIDC_PROVIDER_ISSUER`                    | URL       | `""`                           | No        | OIDC issuer base URL. Discovery is fetched from `${issuer}/.well-known/openid-configuration`.                                                                                              |
| `clientId`                | `OIDC_PROVIDER_CLIENT_ID`                 | string    | `""`                           | No        | OAuth client identifier registered with the provider.                                                                                                                                      |
| `clientSecret`            | `OIDC_PROVIDER_CLIENT_SECRET`             | string    | `""`                           | **Yes**   | OAuth client secret. Inject from a secret store, never commit a real value.                                                                                                                |
| `adminClaim`              | `OIDC_PROVIDER_ADMIN_CLAIM`               | string    | `""`                           | No        | Claim value that grants platform admin. Empty means no one is promoted (deny-by-default).                                                                                                  |
| `scopes`                  | (none)                                    | string\[] | `["openid","email","profile"]` | No        | OAuth scopes requested. Omit to use the default; the provider must return the required claims.                                                                                             |
| `requireIssuerValidation` | `OIDC_PROVIDER_REQUIRE_ISSUER_VALIDATION` | boolean   | `true`                         | No        | Enforce the RFC 9207 authorization-response `iss` parameter. Set `false` only for providers that don't implement it.                                                                       |
| `apiKey`                  | `OIDC_PROVIDER_MFA_API_KEY`               | string    | `""`                           | **Yes**   | FusionAuth server API key for the `OIDC_MFA` wallet-signing method. Authenticates the platform's server-to-server two-factor calls. Inject from a secret store; never commit a real value. |
| `applicationId`           | `OIDC_PROVIDER_MFA_APPLICATION_ID`        | string    | `""`                           | No        | FusionAuth application id that scopes the `OIDC_MFA` two-factor flow. For FusionAuth this is the same value as `clientId`.                                                                 |

### Enablement predicate [#enablement-predicate]

A provider entry activates for sign-in only when `id`, `issuer`, `clientId`, and `clientSecret` are all non-empty. A partially-filled entry parses without error but the platform silently drops it: local login stays active, and no sign-in button appears. `displayName`, `scopes`, and `adminClaim` do not affect activation.

### OIDC MFA enablement predicate [#oidc-mfa-enablement-predicate]

`apiKey` and `applicationId` enable a capability separate from sign-in: the `OIDC_MFA` wallet-signing verification method. When a signing request declares `OIDC_MFA`, the platform runs a server-side FusionAuth TOTP check and treats a successful result as authorization for that one operation. It sits alongside `PINCODE`, `OTP`, and `SECRET_CODES` as a way to pass the signing gate.

A provider is OIDC-MFA-capable when `issuer`, `apiKey`, and `applicationId` are all non-empty. This predicate is independent of the sign-in predicate above:

* A provider can enable OIDC wallet verification without sign-in. Set `issuer`, `apiKey`, and `applicationId`, and leave `clientId` and `clientSecret` empty.
* A provider can enable sign-in without OIDC MFA. Leave `apiKey` and `applicationId` empty.

OIDC wallet verification configuration does not disable local login. Only a complete sign-in entry does that. The platform reuses `issuer` as the FusionAuth base URL for the OIDC MFA calls, so the value that anchors discovery also anchors the two-factor round-trip.

`OIDC_MFA` is available to API and SDK callers that supply it in a request's `walletVerification`. The method is not selectable in the Console sign-in or signing dialogs in this version. See [Troubleshooting](/docs/developers/sso-oidc/troubleshooting) for the verification error codes and [FusionAuth setup](/docs/developers/sso-oidc/fusionauth-setup) for the API key and enrollment steps.

### Issuer and discovery [#issuer-and-discovery]

DALP builds the discovery URL by appending `/.well-known/openid-configuration` to `issuer`. Set `issuer` to the exact base URL the provider advertises as its issuer identifier, with no trailing slash. A mismatch between the configured value and the `iss` claim inside the ID token fails validation.

### Admin claim resolution [#admin-claim-resolution]

`adminClaim` is matched in priority order against the profile claims:

1. If `adminClaim` is empty, the user is never an admin (deny-by-default).
2. If a `roles` array claim contains the `adminClaim` value, the user is an admin.
3. If a `groups` array claim contains the `adminClaim` value, the user is an admin.
4. If a claim named exactly `adminClaim` is the boolean `true` (or the string `"true"`), the user is an admin.
5. Otherwise the user is a regular member.

<Callout type="warning" title="Deny-by-default protects against guessable claims">
  Leaving `adminClaim` empty is the safe default. Avoid a generic value an IdP
  might already emit for unrelated groups. Only a deployment that deliberately
  mints the claim should configure it. Because the role re-derives on every
  login, removing the claim at the IdP demotes the user on their next sign-in.
</Callout>

### Issuer validation and RFC 9207 [#issuer-validation-and-rfc-9207]

`requireIssuerValidation` defaults to `true`, requiring the provider to return the `iss` parameter on the authorization response. RFC 9207 defines this as a mixup-attack defense that matters when several IdPs are in play. Providers that lack RFC 9207 support (FusionAuth included) omit that parameter, so every callback fails with `issuer_missing` until the flag is set to `false` for that entry. The ID token's `iss` claim is still checked against discovery regardless of this flag, so turning off RFC 9207 does not disable issuer checking entirely.

Because the flag accepts environment values, the string `"false"` is parsed as the boolean `false` (not coerced to `true` the way `Boolean("false")` would be). Keep the default `true` and override per provider only where the provider provably lacks RFC 9207 support.

## Claim contract [#claim-contract]

The provider must return these claims for the requested scopes:

* **`name`** (required): account creation fails with `name_is_missing` if absent. Some providers derive `name` from a full-name field rather than first/last name; confirm yours populates it.
* **`email`** plus an honored verification signal: an explicit `email_verified: false` (or `"false"`) is rejected; an omitted `email_verified` is accepted, because a missing claim is not the same as an unverified one.
* **a role or group claim** carrying the `adminClaim` value when the user should be a platform admin.

## Other providers [#other-providers]

Okta, Auth0, Keycloak, and similar issuers use the same fields. The differences are mechanical:

* Set `requireIssuerValidation` according to whether your provider implements RFC 9207. Most modern hosted IdPs do, so keep the default `true`.
* Map the admin signal to whatever your IdP emits, typically a `groups` or `roles` claim you enable on the application or via a claim-mapping rule.
* Ensure the `profile` scope (or your provider's equivalent) returns a populated `name`.

The [FusionAuth setup](/docs/developers/sso-oidc/fusionauth-setup) page shows the full sequence for a provider that needs extra configuration to satisfy this contract.
