> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getbifrost.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# OIDC providers

> Map Okta, Auth0, Keycloak or any OIDC provider's machine clients to Bifrost service accounts by client ID, so services call Bifrost with a client-credentials token.

Services that already authenticate with your identity provider's **client-credentials** flow can call Bifrost with that access token. Bifrost trusts the provider as an issuer, reads the client ID from the token, and runs the request as the service account that client ID is mapped to.

Add the provider as a **Generic OIDC** trusted issuer and set its **workload ID claim**: the claim whose value you enter when mapping a workload, usually the client ID. Values are matched exactly, as the provider writes them, including case.

Bifrost takes a token from a generic issuer only when its workload ID is mapped to a service account. Every other token, including your people's when the same provider runs your SSO, goes through the normal sign-in path untouched. So a generic issuer needs no rule to tell people apart, with one exception: your SSO app's own client ID. People's tokens carry it too, so mapping it would let anyone who signs in run as that service account. Bifrost refuses that mapping until the issuer has a rule only workload tokens pass, set under **Tell people's tokens apart with a rule**.

| Provider | Issuer URL | Workload ID claim | Rule, only to map the SSO app's client ID |
| - | - | - | - |
| Okta | The authorization server's issuer, e.g. `https://acme.okta.com/oauth2/default` | `cid` | `cid` equals the token's `sub` |
| Auth0 | Your tenant domain with a trailing slash, e.g. `https://acme.us.auth0.com/` | `azp` | `gty` equals `client-credentials` |
| Keycloak | The realm URL, e.g. `https://sso.acme.com/realms/acme` | `azp` | `preferred_username` starts with `service-account-` |
| An issuer only workloads use, e.g. a Kubernetes cluster or GitHub Actions | The issuer exactly as tokens carry it in `iss` | `sub` | not needed |

## Step 1: Make tokens addressed to Bifrost

For providers with a **client-credentials** grant, configure the provider so tokens for your services carry Bifrost as their audience:

* **Okta:** use an authorization server whose audience is Bifrost's URL, and a scope your service apps may request.
* **Auth0:** create an API whose identifier is Bifrost's URL, and authorize your machine-to-machine apps for it.
* **Keycloak:** add an audience mapper that puts Bifrost's URL in `aud` for the service-account clients.

Workloads on a Kubernetes cluster or in GitHub Actions don't use a grant; they ask their platform for a token with Bifrost as the audience:

* **Kubernetes:** mount a projected service account token with `audience` set to Bifrost's URL (a `serviceAccountToken` source in a `projected` volume). Its `sub` is `system:serviceaccount:<namespace>:<service account>`, the value you map.
* **GitHub Actions:** give the job `permissions: id-token: write` and request the token with Bifrost's URL as the audience, for example `core.getIDToken('https://bifrost.example.com')` in `actions/github-script`. Its `sub` names the repository and ref, such as `repo:acme/payments:ref:refs/heads/main`.

## Step 2: Add the provider as a trusted issuer

1. In Bifrost, open **User Provisioning**, edit your SSO provider, and go to **Provider Configuration → Workload identity**.
2. Under **Additional trusted issuers**, select **Add issuer**, give it a name, choose **Generic OIDC**, paste the issuer URL, set the audience, and fill in the workload ID claim from the table above. Add the rule only if you will map your SSO app's own client ID.
3. Select **Test**, then save the provider.

This needs the **User Provisioning** permission. Once workloads are mapped on the issuer, its URL and workload ID claim can't change: see [trusted issuers](https://docs.getbifrost.ai/enterprise/workload-identity/overview.md#trusted-issuers).

## Step 3: Map a client to a service account

1. Open the service account under **Governance → Users** and go to **Workload identity**.
2. Select **Add workload identity**, choose the issuer, and enter the value of the issuer's **workload ID claim** as the token carries it: the client ID for Okta, Auth0 and Keycloak, or the `sub` value for an issuer like Kubernetes or GitHub Actions.
3. Select **Add**.

This needs the **User Provisioning → `UpdateWorkloadIdentities`** permission.

If the client ID is your SSO app's and the issuer has no rule, Bifrost refuses the mapping and asks you to add the rule first, and refuses a provider save that removes the rule while such a mapping exists. A mapping that ends up in that state another way, such as when the provider's config is changed in `config.json`, shows **Needs a people rule** and takes no tokens until the rule is back.

## Step 4: Call Bifrost

The service sends its token as the bearer token; with a client-credentials provider, it gets the token from the grant first. For example, with Auth0, with `CLIENT_ID` and `CLIENT_SECRET` exported in the environment. The request body is built from the environment and sent on standard input, so the secret never appears in a command's arguments, where other users on the host could read it:

```bash theme={null}
TOKEN=$(jq -n '{grant_type: "client_credentials", client_id: env.CLIENT_ID, client_secret: env.CLIENT_SECRET, audience: "https://bifrost.example.com"}' \
  | curl -s -X POST https://acme.us.auth0.com/oauth/token -H "Content-Type: application/json" --data-binary @- \
  | jq -r .access_token)

curl https://bifrost.example.com/v1/chat/completions \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"model": "openai/gpt-4o-mini", "messages": [{"role": "user", "content": "Hello"}]}'
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.