Skip to main content

Microsoft Entra ID (Azure AD)

Configure Microsoft Entra ID, formerly known as Azure AD, as the Single Sign-On provider for your Kargo instance.

There are three ways to connect Entra ID. Pick one:

MethodKargo modeAzure objectCredentialGroups fromGroup limit
Native OIDCOIDCApp registration, SPA platformPKCEID-token claim200
Dex OIDCDex, oidc connectorApp registrationClient secretID-token claim200
Dex SAMLDex, saml connectorEnterprise application (non-gallery)Signing certificate, inlineSAML assertion150

Native OIDC is the simplest of the three: Kargo talks to Entra ID directly, with no Dex hop and no client secret. It is also the only method documented here for CLI login. The two Dex methods route through Kargo's built-in Dex instance.

Before you start, you need:

  • An Akuity Platform account with a Kargo instance
  • Admin access to your Kargo instance settings
  • Azure Entra ID access with permission to create App registrations, or Enterprise applications for Dex SAML

Native OIDC

Connect Entra ID directly over OIDC with PKCE. Kargo's UI runs the authorization-code flow as a public client, so there is no client secret and no Dex hop.

Switching modes is non-destructive

Kargo stores the Dex configuration and the direct-OIDC fields side by side and uses a flag to select between them, so you can switch between Dex and OIDC without losing either configuration.

For CLI login (Step 8) you also need the kargo CLI installed.

Step 1: Switch to OIDC mode and note the callback URL

  1. In your Kargo Instance, go to Settings.

  2. In the left panel, search for Access and go to OIDC Config.

    SSO Settings

  1. Toggle Enabled to on.

  2. Select OIDC, not Dex.

  3. The callback URL banner shows:

    https://<your-kargo-hostname>/login

The form changes completely compared with Dex mode: you get Client ID, CLI Client ID, Issuer URL and Additional Scopes instead of a YAML editor and a Secrets tab.

Kargo OIDC Config in OIDC mode, showing the /login callback URL

Leave this page open — you will return to it in Step 5.

Step 2: Register the application in Azure

  1. In the Azure Portal, go to Microsoft Entra IDApp registrations+ New registration.

  2. Name: a descriptive name, for example Kargo-Native-OIDC-EntraID.

  3. Supported account types: Accounts in this organizational directory only (Single tenant).

  4. Redirect URI: change the platform dropdown from Web to Single-page application (SPA), then enter:

    https://<your-kargo-hostname>/login
  5. Click Register.

Registering the application with the SPA platform selected

Select SPA, not Web

This is the most important choice in this guide.

Kargo's UI runs the authorization-code and PKCE exchange from the browser as a public client, with no client secret. Entra's Web platform expects a client secret and does not enable CORS on the token endpoint, so the token exchange fails.

Single-page application is the only platform that supports public-client PKCE with CORS.

On the Overview page, note the Application (client) ID and the Directory (tenant) ID.

No client secret is needed anywhere in this method. PKCE replaces it. If you find yourself creating one, you are on the wrong platform type.

Step 3: Add the CLI platform

The Kargo CLI authenticates with the same authorization-code and PKCE flow, receiving the callback on a local loopback port.

  1. In the application, go to Authentication+ Add a platform.

  2. Choose the Mobile and desktop applications tile.

  3. Ignore the suggested URIs. Under Custom redirect URIs enter:

    http://localhost/auth/callback
  4. Click Configure.

You should now have two platform configurations: SPA for /login, and Mobile and desktop applications for http://localhost/auth/callback. Adding this platform also marks the application as a public client, which the CLI flow requires.

The application with both SPA and mobile/desktop platform configurations

Step 4: Configure token claims

Azure Entra ID does not emit an email claim by default, and groups must be explicitly requested as a claim.

Add the email claim

  1. In the application, go to Token configuration+ Add optional claim.

  2. For Token type, select ID.

  3. Check email. Optionally also check preferred_username and upn.

  4. Click Add.

  5. A banner appears reading "Some of these claims (email) require OpenId Connect scopes…". Tick the checkbox to turn on the Microsoft Graph email permission, then click Add.

Without that checkbox the claim is configured but never appears in the token. The email scope is a basic OpenID Connect scope and does not require admin consent.

Adding the email optional claim

The email claim only carries a value if the user's mail attribute is populated

Entra ID sources it from the directory mail attribute, which is frequently blank on newly created, test, or service accounts even when the UPN looks like an email address.

To check, query Microsoft Graph:

GET https://graph.microsoft.com/v1.0/me?$select=mail,userPrincipalName

A response of "mail": null confirms the problem. You can also look under UsersuserContact InformationEmail.

To fix it you need the User Administrator role: set Contact InformationEmail on the user, or send PATCH /users/{id} with { "mail": "user@yourcompany.com" }.

Alternatively, map Kargo roles on a claim that is always present, such as preferred_username or sub. Kargo accepts any claim name.

Add the groups claim

Add this if you want group-based roles.

  1. Go to Token configuration+ Add groups claim.

  2. Select Security groups, or Groups assigned to the application — see the limit below.

  3. Under the ID token section, select Group ID.

  4. Click Add.

Adding the groups claim

Entra ID group limit in OIDC tokens: 200 groups

Past 200 groups Entra ID drops the groups claim entirely and emits overage indicators (_claim_names and _claim_sources) instead. Kargo has no overage-resolution feature, so affected users silently receive no groups at all, with no error, and group-based roles quietly stop applying.

To avoid this, configure a groups claim filter: select Groups assigned to the application instead of Security groups, so only groups explicitly assigned to the application are emitted. Assign them under Enterprise applicationsyour appUsers and groups.

Assigning groups to an application requires Entra ID P1 or P2.

No API permissions or admin consent are required for this method. The default User.Read plus the basic email scope is sufficient.

Step 5: Complete the Kargo OIDC configuration

Back on the Kargo OIDC Config page with OIDC mode selected, fill in:

FieldValue
Client IDYour Application (client) ID from Step 2
CLI Client IDThe same Application (client) ID
Issuer URLhttps://login.microsoftonline.com/<TENANT_ID>/v2.0
Additional ScopesLeave empty

Replace <TENANT_ID> with your Directory (tenant) ID.

Do not add groups to Additional Scopes

Kargo already requests openid, profile and email by default, and appends offline_access when the identity provider advertises it. Adding a groups scope produces:

AADSTS650053: The application asked for scope 'groups' that doesn't exist on the
resource '00000003-0000-0000-c000-000000000000'.

Microsoft Graph has no groups scope. Groups arrive via the token claim configured in Step 4, never via a scope.

A single Entra ID registration serves both the UI and the CLI, because Entra allows multiple platform configurations on one application. Leaving CLI Client ID blank also works — the UI auto-fills it from Client ID.

Step 6: Map users to Kargo roles

Scroll to Kargo Roles and Permissions. For the Admin role:

  • Claim key: email
  • Claim value: your email address
  • Click Add

Available roles are Admin, Viewer, User, and Project Creator.

For group-based mapping, use claim key groups with the group's Entra ID Object ID as the value, matching the Group ID format chosen in Step 4.

caution

Claim matching is exact string equality — no wildcards, no substring matching, no case folding. If you later change the groups claim format, for example from Group ID to sAMAccountName, every existing mapping must be rewritten. Plan format changes as a coordinated migration.

Click Save.

Step 7: Test the UI login

  1. Open a fresh incognito or private window and go to https://<your-kargo-hostname>.

  2. Click SSO Login.

  3. Sign in with your Entra ID account, and accept the consent prompt if shown. This is basic user consent and needs no admin approval.

  4. You land in the Kargo UI with the role you mapped.

Verify it really is native OIDC with PKCE

The redirect URL should contain:

login.microsoftonline.com/<tenant>/oauth2/v2.0/authorize?…&code_challenge=…&code_challenge_method=S256&redirect_uri=…%2Flogin

code_challenge_method=S256 confirms PKCE, and a redirect_uri ending in /login with no /dex/callback anywhere confirms Dex is bypassed.

Step 8: Test the CLI login

kargo login https://<your-kargo-hostname> --sso

The CLI starts a loopback listener on a free local port, opens your browser to Entra ID, completes the PKCE exchange, and stores the token.

Verify you are authenticated:

kargo get projects

You should see your projects listed.

Native OIDC troubleshooting

AADSTS50011 for the CLI callback

Check the registered URI for stray characters. A trailing bracket, space, or slash pasted in with the URL is easy to miss in the Azure form — the value must be exactly http://localhost/auth/callback.

AADSTS50011 for the UI callback

The redirect URI registered in Azure does not match the callback Kargo actually uses. Read the redirect_uri parameter out of the browser URL when you are redirected to Microsoft — that is the exact value Azure must have registered. For native OIDC it is https://<kargo-host>/login.

AADSTS650053: The application asked for scope 'groups' that doesn't exist

Remove groups from Additional Scopes. Entra ID has no groups scope — groups come from the token claim configured in Step 4.

CORS error, or "client_secret is required" at the token exchange

The application is registered on the Web platform instead of Single-page application (SPA). Kargo's UI is a public client using PKCE, and only the SPA platform supports that with CORS. Add a SPA platform configuration, or recreate the application, with the /login redirect URI.

Login succeeds but the user has no permissions

No role mapping matched. Check Kargo Roles and Permissions: the claim key and value must match the token exactly. Decode the ID token and compare the claim values character for character.

Groups missing, or group-based roles not applying

  • Confirm a groups claim is configured in Azure Token configuration (Step 4)
  • Use the group's Object ID as the mapping value, not the display name
  • Check whether the user exceeds the 200-group ceiling. Kargo has no overage fallback, so affected users get no groups silently — switch to Groups assigned to the application

Only some of a user's groups appear

If the groups claim is set to Groups assigned to the application, only groups explicitly assigned to the application are emitted. Assign the remaining groups under Enterprise applicationsyour appUsers and groups.

If it is set to Security groups, verify the missing groups are actually security-enabled. Microsoft 365 groups and distribution lists are excluded.

email claim missing

You need both the email optional claim, with the Graph email permission enabled, and a populated mail attribute on the user. See Step 4. Alternatively map roles on preferred_username or sub.

Native OIDC summary

ComponentValue
Azure app typeApp registration (single tenant)
UI platformSingle-page application (SPA)
UI redirect URIhttps://<kargo-host>/login
CLI platformMobile and desktop applications
CLI redirect URIhttp://localhost/auth/callback — no port needed
Kargo SSO modeOIDC, not Dex
Issuer URLhttps://login.microsoftonline.com/<TENANT_ID>/v2.0
Client secretPKCE
Additional scopesEmpty; defaults are openid, profile, email
Admin consentNot required
Group token limit200, with no overage fallback in Kargo
CLI commandkargo login https://<kargo-host> --sso
Key gotchasRegister the UI as SPA, not Web; register the CLI loopback URI under Mobile and desktop applications; never add a groups scope; the mail attribute must be set for the email claim

Dex OIDC

Connect Entra ID through Dex's oidc connector, using an app registration and a client secret.

Step 1: Get your Kargo callback URL

  1. In your Kargo Instance, go to Settings.

  2. In the left panel, search for Access and go to OIDC Config.

    SSO Settings

  1. Toggle Enabled to on.

  2. Select the Dex option, not OIDC.

  3. A banner displays your callback URL. Copy it — you will register it in Azure:

    https://<your-kargo-hostname>/dex/callback
note

The Kargo Dex callback path is /dex/callback.

When Dex is selected the page shows the /dex/callback URL; when OIDC (direct) is selected it shows a /login URL. Make sure you copy the /dex/callback one.

Kargo OIDC Config showing the Dex callback URL

Leave this page open — you will come back to fill in the configuration.

Step 2: Register a new application in Azure Entra ID

  1. Log in to the Azure Portal.

  2. Navigate to Microsoft Entra IDApp registrations.

  3. Click + New registration.

  4. Fill in the registration form:

    • Name: a descriptive name, for example Kargo-Dex-OIDC-EntraID
    • Supported account types: Accounts in this organizational directory only (Single tenant)
    • Redirect URI: platform Web, set to https://<your-kargo-hostname>/dex/callback from Step 1
  5. Click Register.

Registering the application in Azure Entra ID

Step 3: Note down application details

On the application's Overview page, note down the Application (client) ID and the Directory (tenant) ID.

Application overview showing client and tenant IDs

Step 4: Create a client secret

  1. In the left sidebar, click Certificates & secrets.

  2. Click + New client secret.

  3. Enter a description, for example Kargo Dex OIDC Secret, and select an expiry such as 12 months.

  4. Click Add.

  5. Copy the secret Value immediately. It is shown only once.

caution

Copy the Value column, not the Secret ID. If you lose it, you will need to create a new one.

Creating a client secret

Step 5: Add the email optional claim

Azure Entra ID does not include an email claim in tokens by default. Kargo requires an email claim to identify users, so you must add it.

  1. In the application, click Token configuration in the left sidebar.

  2. Click + Add optional claim.

  3. For Token type, select ID.

  4. Check email. Optionally also check preferred_username and upn as fallbacks.

  5. Click Add.

  6. If prompted that the claim requires the Microsoft Graph profile permission, tick the box to turn it on, then click Add. This is a profile-level permission and does not require admin consent.

Adding the email optional claim

The email claim only appears if the account has a populated mail attribute

Many test and service accounts have a blank Email field, under UsersuserContact InformationEmail. This causes a missing email claim error at login even when everything else is correct.

See Dex OIDC troubleshooting for both the proper fix and a Dex-side fallback.

Add a groups claim for RBAC

Add this if you want to map Entra ID groups to Kargo roles.

  1. On the Token configuration page, click + Add groups claim.

  2. Select Security groups, or Groups assigned to the application — see the limit below.

  3. Under the ID token section, select Group ID.

  4. Click Add.

Adding the groups claim

Entra ID group token limit (OIDC): 200 groups

If a user belongs to more than 200 groups, Entra ID silently drops the extras from the JWT, which can break group-based RBAC and is hard to diagnose.

To avoid this, configure a groups claim filter: select Groups assigned to the application instead of Security groups, so only groups explicitly assigned to the application are emitted.

Assigning groups to an application requires Entra ID P1 or P2. On lower tiers you can still emit security groups, but stay mindful of the 200-group limit.

Step 6: Configure the Dex connector in Kargo

Back on the Kargo OIDC Config page with Dex enabled, open the Configuration tab and enter the following in the Dex Config editor:

connectors:
- type: oidc
id: azure
name: Azure Entra ID
config:
issuer: https://login.microsoftonline.com/<YOUR_TENANT_ID>/v2.0
clientID: <YOUR_CLIENT_ID>
clientSecret: $ENTRA_CLIENT_SECRET
redirectURI: https://<your-kargo-hostname>/dex/callback
scopes:
- openid
- profile
- email
insecureEnableGroups: true

Replace the placeholders:

  • <YOUR_TENANT_ID> — your Directory (tenant) ID from Step 3
  • <YOUR_CLIENT_ID> — your Application (client) ID from Step 3
  • <your-kargo-hostname> — your Kargo instance hostname from Step 1

Configuration fields explained

FieldDescription
typeMust be oidc for the generic Dex OIDC connector
idUnique identifier for this connector
nameDisplay name for the connector
issuerYour Entra ID v2.0 issuer URL
clientIDThe Application (client) ID from Azure
clientSecretReference to the secret stored in the Secrets tab, prefixed with $
redirectURIMust exactly match the redirect URI registered in Azure (/dex/callback)
scopesOIDC scopes to request — openid, profile and email are standard
insecureEnableGroupsTells Dex to forward the groups claim through to Kargo, needed for group-based roles. The "insecure" naming is Dex's standard wording.

Step 7: Add the client secret

  1. Click the Secrets tab.

  2. Add a new secret:

    • Key: ENTRA_CLIENT_SECRET — no $, just the name
    • Value: the client secret value you copied from Azure
  3. The $ENTRA_CLIENT_SECRET reference in the Dex config resolves to this value.

Adding the client secret in the Secrets tab

Step 8: Map users to Kargo roles

Without a role mapping, a user can authenticate but will have no permissions. Scroll to the Kargo Roles and Permissions section and map a claim to a role.

For the Admin role:

  1. Claim key: email

  2. Claim value: your email address, for example you@yourcompany.com

  3. Click Add.

This grants Admin to any SSO user whose email claim matches.

tip

Once group claims are flowing, you can instead map by groups — claim key groups, value being an Entra ID group's Object ID. This is the more scalable pattern for teams. Available roles are Admin, Viewer, User, and Project Creator.

Mapping a claim to a Kargo role

Step 9: Save and test

  1. Click Save in the top right.

  2. Open an incognito or private browser window and go to your Kargo URL, https://<your-kargo-hostname>.

  3. On the Kargo login screen, click SSO Login.

  4. You are redirected to Microsoft. Sign in with your Entra ID account.

  5. Accept the user consent prompt if shown. This is basic profile access and requires no admin consent.

  6. You are redirected back and land in the Kargo UI with the role you mapped.

Kargo login screen with the SSO Login option

Dex OIDC troubleshooting

Failed to authenticate: missing email claim, not found "email" key

Dex could not find an email claim in the token from Entra ID. There are two parts to the fix.

The proper fix, recommended for real users:

  1. Add the email optional claim to the ID token (Step 5), and

  2. Ensure the user account has its Email (mail) attribute populated, under UsersuserContact InformationEmail. Setting this requires User Administrator rights.

The fallback, for accounts whose mail attribute cannot be set such as test or service accounts: tell Dex to read the email from the preferred_username claim, which Entra ID emits by default as the user's UPN. Add these two lines to the connector config:

insecureSkipEmailVerified: true
claimMapping:
email: preferred_username
  • claimMapping.email: preferred_username — Dex uses the preferred_username claim as the email.
  • insecureSkipEmailVerified: true — required because preferred_username has no accompanying email_verified flag.

The resulting email will be the user's UPN, for example user@yourcompany.com. Make sure your Kargo role mappings use that value.

AADSTS54005: OAuth2 Authorization code was already redeemed

This is not a configuration problem. An authorization code was used twice, usually from refreshing the callback page or using the browser back button on a URL containing ?code=…. Start a fresh login from the Kargo login page, and do not refresh the callback page.

Groups not appearing, or RBAC not working

  • Confirm insecureEnableGroups: true is in the connector config
  • Confirm a groups claim is added in Azure Token configuration (Step 5)
  • Map roles using the group's Object ID, not the display name
  • Check whether the user exceeds the 200-group token limit (Step 5)

Client secret errors

  • Ensure the Secrets tab key matches the $ reference in the YAML exactly (ENTRA_CLIENT_SECRET)
  • Verify the secret has not expired in Azure, under Certificates & secrets

Dex OIDC summary

ComponentValue
Azure app typeApp registration (single tenant)
Redirect URIhttps://<kargo-hostname>/dex/callback
Kargo SSO modeDex, type: oidc connector
OIDC issuerhttps://login.microsoftonline.com/<TENANT_ID>/v2.0
Required scopesopenid, profile, email
Secret reference$ENTRA_CLIENT_SECRET
Admin consentNot required
Group token limit200 (OIDC)
Key gotchaEntra ID omits the email claim by default — add the optional claim and ensure the mail attribute is set, or use the claimMapping fallback

Dex SAML

Connect Entra ID through Dex's saml connector, using a non-gallery Enterprise Application and a signing certificate.

Use a non-gallery Enterprise Application — not an App registration

SAML SSO can only be configured on a non-gallery Enterprise Application. If you create the app via App registrationsNew registration, or the "Register an application…" option, you get an OIDC app whose Single sign-on page offers no SAML option, and it cannot be converted.

You must create it via Enterprise applicationsCreate your own applicationIntegrate any other application you don't find in the gallery (Non-gallery).

For this method you need Azure Entra ID access with permission to create Enterprise Applications — Application Administrator, Cloud Application Administrator, or Owner of the app.

Step 1: Get your Kargo callback URL for SAML

  1. In your Kargo Instance, go to Settings.

  2. In the left panel, search for Access and go to OIDC Config.

    SSO Settings

  1. Toggle Enabled to on.

  2. Select the Dex option.

  3. Copy the callback URL shown:

    https://<your-kargo-hostname>/dex/callback
note

Kargo's Dex callback path is /dex/callback. This single URL is used as both the SAML Identifier (Entity ID) and the Reply URL (ACS).

Kargo OIDC Config showing the Dex callback URL

  1. In the Azure Portal, go to Microsoft Entra IDEnterprise applications.

  2. Click + New application+ Create your own application.

  3. Enter a name, for example kargo-saml.

  4. Select Integrate any other application you don't find in the gallery (Non-gallery) — the bottom option.

  5. Click Create.

Step 3: Configure basic SAML configuration

  1. In the new application, click Single sign-on in the left sidebar and select the SAML card.

  2. In section 1, Basic SAML Configuration, click the pencil icon and set:

    FieldValue
    Identifier (Entity ID)https://<your-kargo-hostname>/dex/callback
    Reply URL (ACS URL)https://<your-kargo-hostname>/dex/callback
    Sign on URLhttps://<your-kargo-hostname>/login
    Relay State / Logout URLLeave empty
  3. Click Save.

Basic SAML configuration

Basic SAML configuration saved

Step 4: Configure user attributes and claims

In section 2, Attributes & Claims, click Edit.

Add the email attribute by clicking + Add new claim:

  • Name: email
  • Namespace: leave empty
  • Source: Attribute
  • Source attribute: user.mail
  • Click Save
warning

If the account's Email (mail) attribute is blank, which is common for test and service accounts, use user.userprincipalname as the source attribute instead. Otherwise the email attribute will be empty and login fails. Check under UsersuserContact InformationEmail.

Add the group attribute by clicking + Add a group claim:

  • Which groups: Security groups, or Groups assigned to the application — see the limit below
  • Source attribute: Group ID
  • Tick Customize the name of the group claim
  • Name: Group
  • Leave Emit groups as role claims unchecked
  • Click Save

Leave the Unique User Identifier / Name ID at its default, user.userprincipalname.

SAML attributes and claims

Entra ID group token limit (SAML): 150 groups

If a user is a member of more than 150 groups, Entra ID silently drops the extras from the SAML assertion, which can break group-based RBAC and is hard to diagnose.

To avoid this, configure a groups claim filter: choose Groups assigned to the application instead of Security groups, so only groups explicitly assigned to the application are emitted. Assigning groups to an application requires Entra ID P1 or P2.

Step 5: Download the SAML signing certificate

  1. In section 3, SAML Certificates, find Certificate (Base64).

  2. Click Download and save the .cer file.

Downloading the SAML signing certificate

Step 6: Copy the login URL

In section 4, Set up app name, copy the Login URL. It will look like:

https://login.microsoftonline.com/<YOUR_TENANT_ID>/saml2

This becomes ssoURL in the Dex config.

Step 7: Assign users to the application

SAML only issues assertions for assigned users.

  1. In the application, go to Users and groups in the left sidebar, then click + Add user/group.

  2. Add your user, and any groups, then click Assign.

Assigning users to the application

Step 8: Base64-encode the certificate

The Dex caData field needs the certificate as a single-line base64 string. On macOS:

cat ~/Downloads/<your-cert>.cer | base64 | tr -d '\n' | pbcopy

This copies a clean single-line base64 value to your clipboard. The signing certificate is public — it is not a secret.

Step 9: Configure the Dex SAML connector in Kargo

Back on the Kargo OIDC Config page with Dex enabled, open the Configuration tab and replace the Dex Config with the following:

connectors:
- type: saml
id: saml
name: Azure Entra ID
config:
ssoURL: https://login.microsoftonline.com/<YOUR_TENANT_ID>/saml2
entityIssuer: https://<your-kargo-hostname>/dex/callback
redirectURI: https://<your-kargo-hostname>/dex/callback
caData: <PASTE_SINGLE_LINE_BASE64_CERT>
usernameAttr: email
emailAttr: email
groupsAttr: Group

Replace the placeholders:

  • <YOUR_TENANT_ID> — your Directory (tenant) ID
  • <your-kargo-hostname> — your Kargo instance hostname from Step 1
  • <PASTE_SINGLE_LINE_BASE64_CERT> — the base64 string from Step 8
note

No Secrets tab entry is needed for SAML — the certificate is inline and public.

groupsAttr is optional

If your test user is not a member of any group, remove the groupsAttr: Group line. Otherwise Dex fails with no attribute with name "Group", because Entra ID omits the group claim entirely when the user has no groups. Add it back once the user belongs to at least one group.

Configuration fields explained

FieldDescription
typeMust be saml
ssoURLThe Login URL from Azure, the /saml2 endpoint
entityIssuerMust match the Identifier (Entity ID) set in Azure (/dex/callback)
redirectURIMust match the Reply URL / ACS in Azure (/dex/callback)
caDataBase64-encoded SAML signing certificate
usernameAttrSAML attribute used as the username (email)
emailAttrSAML attribute used as the email (email)
groupsAttrSAML attribute used for groups (Group) — optional

Step 10: Map users to Kargo roles

Scroll to Kargo Roles and Permissions. For the Admin role:

  • Claim key: email
  • Claim value: your email or UPN, for example you@yourcompany.com
  • Click Add
tip

Available roles are Admin, Viewer, User, and Project Creator. Once group claims are flowing, you can map by groups, with the value being the group's Object ID, for team-based RBAC.

Step 11: Save and test the SAML login

  1. Click Save and confirm the "Unsaved changes" indicator clears.

  2. Open a fresh incognito window, go to https://<your-kargo-hostname>, and click SSO Login.

  3. You are redirected to Microsoft. Sign in.

  4. You land in the Kargo UI with the role you mapped.

Verify it really is using SAML

The redirect URL should be https://login.microsoftonline.com/<tenant>/saml2?SAMLRequest=… — note /saml2 and SAMLRequest.

If you instead see /oauth2/v2.0/authorize?…client_id=…, Kargo is still using an OIDC connector. Re-check that the Dex Config contains only the saml connector and was saved, then start the login from a fresh window.

Dex SAML troubleshooting

Single sign-on page only offers OIDC, with no SAML option

The app was created as an App registration (OIDC), not a non-gallery Enterprise Application. App-registration apps cannot do SAML and cannot be converted. Delete it and recreate via Enterprise applicationsCreate your own applicationIntegrate any other application… (Non-gallery).

Login redirects to /oauth2/v2.0/authorize instead of /saml2

Kargo is still running an OIDC connector. Make sure the Dex Config contains only the type: saml connector, with no leftover type: oidc block, that it was saved, and start the login from a brand-new window. A stale tab can replay the old OIDC URL.

Failed to authenticate: no attribute with name "Group"

Entra ID only emits the group claim if the user belongs to at least one group. If groupsAttr is set but the user has no groups, Dex fails. Either add the user to a group, or remove groupsAttr if you do not need group-based RBAC.

Failed to authenticate: missing email claim, or an empty email

The email SAML claim is empty. Ensure the email claim exists in Attributes & Claims and that its source attribute points at a populated field — user.mail for accounts with a mailbox, or user.userprincipalname for accounts whose mail attribute is blank.

Certificate or signature errors

  • Confirm caData is the base64-encoded signing certificate from Step 8, with no stray line breaks
  • Confirm you downloaded Certificate (Base64), not Raw or Federation Metadata
  • Re-download and re-encode if Azure rotated the signing certificate

Dex SAML summary

ComponentValue
Azure app typeEnterprise Application (non-gallery)
SAML Identifier / Reply URLhttps://<kargo-hostname>/dex/callback
Sign on URLhttps://<kargo-hostname>/login
Kargo SSO modeDex, type: saml connector
ssoURLhttps://login.microsoftonline.com/<TENANT_ID>/saml2
CredentialSAML signing certificate, inline caData, public
Secret referenceNone — SAML uses the certificate
Admin consentNot required
Group token limit150 (SAML)
Key gotchasMust use a non-gallery Enterprise App; email source user.mail or user.userprincipalname; groupsAttr is optional, since Entra ID omits it when the user has no groups