Configure Dex to Use Microsoft Entra ID as an OIDC Connector
PaletteAI authenticates users through Dex, which can broker authentication to an external OpenID Connect (OIDC) provider. This page shows how to configure Dex to use Microsoft Entra ID (formerly Azure Active Directory) as its OIDC provider so that PaletteAI users sign in with their Entra ID credentials.
The authentication flow is: user -> PaletteAI -> Dex -> Microsoft Entra ID -> Dex -> PaletteAI.
When Palette and PaletteAI both authenticate against the same Entra ID tenant, use the oidc Dex connector type. Palette's recommended single sign-on configuration maps the user email to the preferred_username claim, and the oidc connector lets you apply the same claim mapping in PaletteAI so that both products identify users the same way. This page uses the oidc connector as the primary path and documents the alternative microsoft connector in Alternative: The Microsoft Connector.
Dex can connect to many OIDC providers. Microsoft Entra ID is one example. For the full list and per-provider configuration, refer to the upstream Dex connectors reference.
Prerequisites
-
A Microsoft Entra ID tenant with permission to create an application registration.
-
A running PaletteAI installation. If you have not installed PaletteAI yet, complete the Self-Hosted Quickstart or one of the following installation guides: Vanilla Kubernetes, AWS IaaS, or GKE.
-
Access to the Helm values used to install PaletteAI. For Flux-managed and appliance installations, access to edit the
muralHelmReleasein themural-systemnamespace instead.
This page only configures user sign-in through Entra ID. To control what each authenticated user can do in the cluster, follow either Configure Kubernetes API Server to Trust OIDC Provider or Configure User Impersonation to enforce per-user Role-Based Access Control (RBAC).
The two enforcement paths are mutually exclusive. If you configure the Kubernetes API server to trust Dex, do not also enable user impersonation. Refer to Configure User Impersonation, which documents this restriction in detail.
Enablement
Register the Application in Microsoft Entra ID
PaletteAI needs its own application registration in Entra ID, separate from the one Palette uses. Both registrations can live in the same Entra ID tenant. Keeping the registrations separate also avoids a logout conflict: an Entra ID application registration accepts only one front-channel logout URL, and Palette and PaletteAI redirect to different logout endpoints after sign-out.
-
In the Entra ID admin center, create a new application registration for PaletteAI. Refer to the Microsoft Register an application quickstart for the exact steps.
-
Add a Web platform redirect URI of
https://<your-paletteai-domain>/dex/callback. This value must match theredirectURIfield in the Dex connector configuration exactly. A difference as small as a trailing slash causes a sign-in failure. -
Create a client secret for the application and copy its value. The copied value becomes the
clientSecretin the Dex connector configuration. Store it securely, because Entra ID displays the secret value only once. -
Record the following values from the application registration. You reference them in the Dex connector configuration:
-
The Application (client) ID.
-
The Directory (tenant) ID.
-
-
(Optional) If you want Entra ID to forward group membership to PaletteAI, add a groups claim to the token configuration of the application registration. Refer to Group Claims for how Dex reads the claim and how the format differs between connector types.
Configure the Dex Connector
Add an Entra ID connector to your PaletteAI Helm values.yaml under dex.config.connectors. Replace the placeholders with the values recorded in Register the Application in Microsoft Entra ID.
dex:
config:
connectors:
- type: oidc
id: entra # For Tenant-scoped connectors, use entra_<tenant-subdomain>.
name: Microsoft Entra ID
config:
issuer: https://login.microsoftonline.com/<tenant-id>/v2.0
clientID: <client-id>
clientSecret: <client-secret>
redirectURI: https://<your-paletteai-domain>/dex/callback
getUserInfo: true
insecureSkipEmailVerified: true
claimMapping:
email: preferred_username
overrideClaimMapping: true
scopes:
- openid
- profile
- email
Each of the following fields is required for the Entra ID integration to work:
-
issueruses the tenant-specific v2.0 endpoint. Substitute the Directory (tenant) ID for<tenant-id>. -
claimMapping.email: preferred_usernamemaps the Entra IDpreferred_usernameclaim to Dex's internalemailfield. This matches Palette's recommended single sign-on mapping, so a user has the same identity in Palette and PaletteAI. Note thatpreferred_usernameis a mutable Entra ID claim and can be an email address, phone number, or user principal name. If it changes for a user, the identity that Dex maps changes with it, so treat it as a sign-in identity rather than a permanent identifier. -
overrideClaimMapping: trueis required alongside theemailmapping. By default theoidcconnector appliesclaimMapping.emailonly when the token has no standardemailclaim. Because theemailscope prompts Entra ID to include a nativeemailclaim, Dex would otherwise use that claim and ignore thepreferred_usernamemapping. SettingoverrideClaimMapping: trueforces Dex to apply the mapping even when anemailclaim is present. -
getUserInfo: trueforces Dex to fetch claims from theuserinfoendpoint rather than relying only on the ID token. Entra ID returns the claims PaletteAI needs through this endpoint. -
insecureSkipEmailVerified: trueprevents Dex from rejecting users whose email verification status it cannot confirm from the upstream provider. Entra ID does not return anemail_verifiedclaim through this connector path, so without this setting Dex rejects the sign-in because theemailscope requires the claim. When the setting is enabled and the claim is absent, Dex defaults the value totrue. Treat this as a compatibility override for providers that omit the claim, not as proof that Entra ID verified the mapped email. Theinsecureprefix is historical and reflects that Dex is no longer enforcing the check itself. Refer to the upstream Dex OIDC connector reference for details. -
redirectURImust use the public PaletteAI URL: Entra ID redirects the user's browser to this URL after authentication, and the value must be registered on the application in Entra ID.
Your existing Dex static clients and static passwords remain unchanged. The Entra ID connector coexists with local Dex users. At the sign-in page, users can either enter credentials for a local Dex user or select the Entra ID connector.
Alternative: The Microsoft Connector
Dex also provides a dedicated microsoft connector for Entra ID. Choose it when you want PaletteAI to authenticate against Entra ID on its own terms rather than share Palette's claim format.
The connectors differ in the following ways:
| Consideration | oidc connector | microsoft connector |
|---|---|---|
| Email claim | Maps preferred_username to the email through claimMapping.email, matching Palette. | Reads the Microsoft Graph userPrincipalName directly; no claimMapping is required. |
| Group claim format | Returns whatever Entra ID places in the token, usually group GUIDs, matching Palette. | Returns group display names by default. Set groupNameFormat: id to return GUIDs. |
The following example configures the microsoft connector with GUID-formatted groups:
dex:
config:
connectors:
- type: microsoft
id: entra
name: Microsoft Entra ID
config:
clientID: <client-id>
clientSecret: <client-secret>
redirectURI: https://<your-paletteai-domain>/dex/callback
tenant: <tenant-id>
groupNameFormat: id
-
tenantis the Directory (tenant) ID of your Entra ID tenant. -
groupNameFormat: idmakes the connector return group GUIDs instead of display names, so the group values match the format Palette receives from the same tenant. Omit this field to receive group display names. -
groupsrequires the user to be a member of at least one listed group to sign in; it does not by itself limit which groups Dex emits in the claim. AdduseGroupsAsWhitelist: trueto also restrict the emitted groups to the ones listed ingroups. Values ingroupsmust match the connector'sgroupNameFormat: group names by default, or group GUIDs whengroupNameFormat: idis set.
Refer to the upstream Dex Microsoft connector reference for the full field list.
Group Claims
If you map Entra ID groups to Kubernetes groups for RBAC, configure Dex to read and forward the group claim. The required fields depend on the connector type.
For the oidc connector:
-
Add
insecureEnableGroups: trueto the connectorconfigblock. This setting is required for theoidcconnector to read and forward group claims from upstream providers. Theinsecureprefix is historical and dates from when the feature was experimental, not from any security concern. Because the standard OIDC refresh flow does not re-fetch the groups claim, group membership can go stale between sign-ins until the next full authentication. -
Configure the application registration in Entra ID to emit the groups claim, as described in the optional groups-claim step of Register the Application in Microsoft Entra ID. Entra ID emits groups through the token configuration, not through an OAuth scope, so no
groupsscope is added to the connector.
The oidc connector then returns whatever Entra ID places in the group claim, which is usually a list of group GUIDs.
Entra ID limits the groups claim to 200 group memberships in JWT and OIDC tokens. When a user exceeds the limit, Entra ID omits the groups claim and instead emits a _claim_names and _claim_sources indirection that points to a Microsoft Graph endpoint. The oidc connector reads groups directly from the claim and does not resolve this indirection, so a user in more than 200 groups signs in with no groups. For tenants with large or deeply nested group membership, use the microsoft connector, which fetches groups from Microsoft Graph and is not subject to the token limit. Refer to the Microsoft ID token claims reference for details.
For the microsoft connector, Dex fetches group membership from Microsoft Graph automatically, so insecureEnableGroups does not apply and the Entra ID token configuration is not involved. This requires the Directory.Read.All Microsoft Graph permission on the PaletteAI application registration, with administrator consent granted. Control the result through the groups and groupNameFormat fields shown in Alternative: The Microsoft Connector, along with the other group options in the upstream Dex Microsoft connector reference. By default the connector returns group display names; set groupNameFormat: id to return GUIDs instead. Because the connector reads groups from Graph on each sign-in, it is not subject to the token overage limit described above.
The group values that either connector forwards, such as Entra ID group GUIDs, are not PaletteAI RBAC groups on their own. You must still map them to Kubernetes groups. When the Kubernetes API server trusts Dex directly, the group values must resolve to the canonical pai:tenant:<tenant-name>:role:... groups that PaletteAI RBAC expects. When you use user impersonation instead, map the forwarded group values with canvas.impersonationProxy.groupMap. Both paths are documented in Configure Kubernetes API Server to Trust OIDC Provider and Configure User Impersonation. Use the format that matches those mappings and, when Palette and PaletteAI share a tenant, the format Palette receives.
Scope Connectors per Tenant
If each Tenant has its own subdomain, you can name a Dex connector <prefix>_<subdomain>, for example entra_tenant-1, so it appears only on that Tenant's sign-in page. Refer to Scope Connectors per Tenant for the naming convention, matching rules, and troubleshooting guidance.
Configure PaletteAI for OIDC
In the same values.yaml, configure the PaletteAI OIDC settings.
canvas:
oidc:
sessionSecret: '' # leave empty; populated via global.auth.sessionSecret
sessionDir: '/app/sessions'
issuerK8sService: '' # leave empty; automatically configured in the Helm chart templates
skipSSLCertificateVerification: false
redirectURL: 'https://<your-paletteai-domain>/ai/callback'
Set skipSSLCertificateVerification to true only when Dex presents a self-signed certificate that the PaletteAI UI cannot otherwise trust.
Apply the Configuration
Apply the changes with Helm.
helm upgrade mural oci://public.ecr.aws/mural/mural \
--namespace <namespace> \
--version <version> \
--values <values-file> \
--atomic --timeout 5m
After the upgrade completes, restart Dex and the PaletteAI UI so they pick up the new configuration.
kubectl rollout restart deployment dex --namespace <namespace>
kubectl rollout restart deployment canvas --namespace <namespace>
For Flux-managed and appliance installations, update the values in the mural HelmRelease instead of running helm upgrade. Refer to Apply the Configuration for the full workflow.
Validate
-
Sign in to PaletteAI. Your browser is redirected to Dex, then to Microsoft Entra ID, and finally back to PaletteAI, where you are signed in.
-
Confirm that Dex accepted the identity from Entra ID.
kubectl logs --namespace <namespace> --selector app.kubernetes.io/name=dex --tail=20Look for a
login successfulentry that records the user email. If you configured group claims, confirm that the same entry contains agroups=[...]list. An entry ofgroups=[]indicates that the connector did not receive the claim. Refer to Common Issues. -
Confirm that the user identity in PaletteAI matches the identity in Palette. Because the
oidcconnector mapsemailtopreferred_username, the signed-in user email in PaletteAI is the same value Palette shows for the same user.
Common Issues
Invalid Redirect URI from Entra ID
The redirectURI in the Dex connector configuration must exactly match a redirect URI registered on the PaletteAI application in Entra ID. Differences as small as a trailing slash cause this error. Inspect the redirect_uri query parameter in the browser address bar to confirm the exact value Dex is sending, and confirm that https://<your-paletteai-domain>/dex/callback is registered as a Web redirect URI on the application.
User Rejected for Unverified Email
If sign-in fails because Dex cannot confirm the user's email verification status, confirm that insecureSkipEmailVerified: true is set in the connector config block. Entra ID does not return an email_verified claim through this connector path, and the email scope requires the claim, so Dex rejects the user without this setting. This applies to the oidc connector; the microsoft connector does not use the email scope.
Wrong Email Value in PaletteAI
If the signed-in user email does not match the value Palette shows, confirm that both claimMapping.email: preferred_username and overrideClaimMapping: true are set. Without the mapping, Dex uses the default email claim, which can differ from the preferred_username value that Palette maps. Without overrideClaimMapping: true, Dex ignores the mapping whenever the token already carries a native email claim, which the email scope prompts Entra ID to include.
Empty Groups in Dex Logs
When groups=[] appears in the Dex logs after a successful sign-in through the oidc connector, confirm the following:
-
insecureEnableGroups: trueis set in the connectorconfigblock. -
The application registration in Entra ID is configured to emit the groups claim in its token configuration, and the user is a member of at least one group.
-
The user is not over the Entra ID group overage limit. When a user belongs to more than 200 groups, Entra ID omits the
groupsclaim from the token, and theoidcconnector reports no groups. Switch the affected users to themicrosoftconnector, which reads groups from Microsoft Graph. Refer to Group Claims for the full explanation.
For the microsoft connector, empty groups usually mean the Directory.Read.All Microsoft Graph permission is missing or has not received administrator consent on the PaletteAI application registration.
Single Logout URL Conflict Between Palette and PaletteAI
An Entra ID application registration has one front-channel logout URL. Palette and PaletteAI redirect to different logout endpoints after sign-out, so if the two share a single application registration, only one product's logout endpoint can be configured, and signing out of the other product fails to redirect correctly. Use separate application registrations for Palette and PaletteAI, as described in Register the Application in Microsoft Entra ID, so each can set its own front-channel logout URL.
Connector Not Visible on the Expected Tenant Subdomain
If a Tenant-scoped connector does not appear on its Tenant subdomain, or appears on the wrong subdomain, refer to Troubleshoot Tenant-Scoped Connectors.
Next Steps
Dex now authenticates users through Microsoft Entra ID. To finish, choose how Kubernetes enforces per-user RBAC:
-
For clusters where you control the Kubernetes API server flags, refer to Configure Kubernetes API Server to Trust OIDC Provider.
-
For managed clusters, or when you also need to grant permissions to local Dex users through
dexGroupMap, refer to Configure User Impersonation.
If you rely on direct OIDC group enforcement, Kubernetes RBAC enforcement is UI-only until the Kubernetes API server is configured to use Dex as its OIDC provider. Any user with a valid kubeconfig bypasses OIDC group enforcement and is authorized solely by the credentials in that kubeconfig. User impersonation is a separate enforcement path and does not depend on the API server trusting Dex.
To add, update, or remove connectors on a running installation, refer to Manage Dex Connectors.