Prerequisites
- A Zitadel instance (cloud at
*.zitadel.cloudor self-hosted) with admin access - An existing Zitadel Project in the organization you want to connect
- Bifrost Enterprise deployed and accessible
- Your Bifrost callback URL:
https://<your-bifrost-domain>/login - Bifrost roles created for the roles you plan to map
Step 1: Create a web application
Add a new application to your project
Open the Zitadel Console and go to Projects → your project → New Application.Give it a name - e.g. 
Bifrost OIDC - and select Web as the application type.
Configure redirect URIs
On the Redirect URIs step, add your login callback to Redirect URIs:Optionally, to use the Discover Claims feature during Bifrost setup, also add:Discover Claims opens a one-time sign-in popup during configuration so Bifrost can inspect the exact JWT your Zitadel tenant sends - useful for verifying role claims are present before you build your attribute mappings. You can skip it and add the URL later if needed.

Step 2: Enable role claims on the project (optional)
Skip this step if you plan to map roles using a different claim (e.g. groups or a custom attribute) rather than Zitadel project roles.
Enable Return user roles during authentication
Open Projects → your project → General and enable:
Note the Project ID - you will need it for the Bifrost configuration.
- Return user roles during authentication - required for role claims to appear in the token
- Only authorized users can authenticate - enforces that every user has at least one project role

Without Return user roles during authentication, the token will not contain role claims and every user will fall back to the default role.
Step 3: Create project roles (optional)
Add roles to the project
In the same project, open the Roles tab and create a role for each Bifrost role you plan to map (e.g. 
Bifrost-Admin, Bifrost-Viewer).
Step 4: Configure token settings
Step 5: Create a service account for bulk sync (optional)
This step is only required if you want Bifrost to import users in bulk and sync them in the background every 24 hours. If you only need SSO login, skip this step.
Create the service account
Navigate to Users → Service Accounts → New.Name it (e.g.
Bifrost Service Account) and create it.Generate a client secret
Open the service account and go to Actions → Generate Client Secret.
Copy the Client ID and Client Secret immediately - the secret is shown only once.

Step 6: Configure Bifrost
Open User Provisioning and choose Zitadel
In your Bifrost dashboard, go to Governance → User Provisioning.Select Zitadel as the identity provider and click Next.

Fill in the provider configuration
Enter the credentials you collected in the steps above:
Click Verify & Next to confirm the connection.
| Field | Value |
|---|---|
| Domain | Your Zitadel host, e.g. my-instance.zitadel.cloud or auth.company.com (no scheme, no path) |
| Project ID | Project ID from Step 2 |
| Client ID | Web Application Client ID from Step 1 |
| Audience | Optional access-token audience override |
| Service Account Client ID | From Step 5 (optional - bulk sync only) |
| Service Account Client Secret | From Step 5 (optional - bulk sync only) |

Discover claims
On the Attribute Mapping screen, click Discover Claims.Bifrost opens a sign-in popup - no session is created.Once you authenticate, it returns the exact claims your Zitadel tenant is sending in the JWT - including project roles, groups, and any custom metadata. Use this to confirm the
urn:zitadel:iam:org:project:roles claim is present before building your mappings.Set up attribute mappings
Use the sections below the claim list to map Zitadel claim values to Bifrost roles, teams, and business units.Attribute-to-Role MappingsMap a claim value to a Bifrost role.
Click Next when done.
- All matching rules are evaluated - if multiple rules match, the role with the highest permissions is assigned
- If no rule matches, the user is not assigned a role and login is denied
- Use a specific value (e.g.
engineering) to map that exact claim value to a named Bifrost team - Use
*as the value to sync the claim value directly as the team name - Use
${*}to extract part of the string - e.g.Bifrost Playground: ${*} TeammatchesBifrost Playground: Alpha Teamand creates team Alpha
- Use a specific value (e.g.
platform) to map that exact claim value to a named Bifrost business unit - Use
${*}to extract a substring as the business unit name - e.g.Bifrost Playground: ${*} BUmatchesBifrost Playground: Alpha BUand creates business unit Alpha - When a rule matches, the resolved business unit is assigned to all of that user’s teams
- Manually assigned teams are left unchanged

How background sync works
Bifrost uses the service account credentials from this setup to sync users in the background every 24 hours. During that sync, Bifrost reconciles imported users, role mappings, team mappings, and business-unit mappings from Zitadel. Every 15 minutes, Bifrost also refreshes active OIDC sessions. If a session cannot be refreshed, Bifrost checks with Zitadel whether the user is still active; if Zitadel reports the user as inactive, Bifrost decommissions that user locally.Troubleshooting
Role claims missing in the token - enable Return user roles during authentication on the project (Step 2) and ensure the user has an active role authorization for the project.invalid audience when validating the JWT - check the audience field in Bifrost. It must match the aud claim issued by Zitadel. Leaving it empty uses the project resource owner as the audience.
Service account cannot list users - confirm the service account has Org User Manager or Org Owner Viewer role in the organization. Regenerate the client secret if you’ve lost it - the original cannot be retrieved.
Redirect URI mismatch - Zitadel requires an exact string match. Check for trailing slashes and http vs https.





