Skip to main content
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.

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.

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: