Skip to main content
Version: v1.1.x

Manage Dex Connectors

PaletteAI authenticates users through Dex, which brokers authentication to external identity providers through connectors. Connectors are defined in the PaletteAI Helm values under dex.config.connectors. This page explains how to add, update, and remove connectors on a running PaletteAI installation, how to apply the change, and what happens to users who are signed in when the change takes effect.

For a worked end-to-end example that configures a specific provider, refer to Configure Dex to Use Keycloak as an OIDC Connector. For the fields each connector type accepts, refer to the upstream Dex connectors reference.

How Connector Changes Are Applied

The PaletteAI Helm chart renders the entire dex.config block into a Kubernetes Secret that the Dex pod reads at startup. The PaletteAI UI reads the same configuration at startup to build the sign-in page and filter connectors per Tenant. Every connector change therefore follows the same cycle, regardless of whether you are adding, updating, or removing a connector:

  1. Edit the connector list in your Helm values.

  2. Apply the values with helm upgrade, or through the mural HelmRelease for Flux-managed and appliance installations.

  3. Restart the dex and canvas deployments so both pick up the new configuration.

warning

Helm replaces lists instead of merging them. The dex.config.connectors list in your values must always contain the complete set of connectors you want configured. An entry that is missing from the list is removed from the running configuration.

Prerequisites

  • A running PaletteAI installation. If you have not installed PaletteAI yet, complete the Self-Hosted Quickstart or one of the installation guides.

  • kubectl access to the PaletteAI hub cluster.

  • Access to the Helm values used to install PaletteAI. For Flux-managed and appliance installations, access to edit the mural HelmRelease in the mural-system namespace instead.

  • When adding or updating a connector, an OAuth2 or OIDC client registered with the identity provider, including the client ID, client secret, and https://<your-paletteai-domain>/dex/callback registered as a valid redirect URI.

Add a Connector

  1. Register a client with the identity provider and set its redirect URI to https://<your-paletteai-domain>/dex/callback. The exact steps vary by provider. Refer to the upstream Dex connectors reference for provider-specific instructions.

  2. Append the new connector to the dex.config.connectors list in your Helm values. The following example adds a GitHub connector alongside an existing Tenant-scoped OIDC connector.

    dex:
    config:
    connectors:
    # Existing connector, kept in the list
    - type: oidc
    id: keycloak_tenant-1
    name: Keycloak (Tenant 1)
    config:
    issuer: https://keycloak.example.com/realms/tenant-1
    clientID: dex
    clientSecret: <keycloak-client-secret>
    redirectURI: https://tenant-1.example.com/dex/callback
    # New connector
    - type: github
    id: github
    name: GitHub
    config:
    clientID: <github-client-id>
    clientSecret: <github-client-secret>
    redirectURI: https://<your-paletteai-domain>/dex/callback
  3. Choose the id deliberately. Each connector id must be unique, and Dex associates issued tokens with it. In a multi-tenant deployment, an id without an underscore appears on every Tenant sign-in page, while an id of the form <prefix>_<subdomain> appears only on the matching Tenant subdomain. Refer to Scope Connectors per Tenant for the full matching rules.

  4. Continue with Apply the Configuration.

Update an Existing Connector

  1. Edit the connector entry in place in dex.config.connectors. Typical updates include rotating a clientSecret, changing scopes or claimMapping, pointing issuer at a new provider URL, or changing the display name shown on the sign-in page.

  2. Keep the provider registration in sync. If you change redirectURI, the new value must also be registered with the identity provider, and if you rotate a client secret on the provider side, update clientSecret in the connector configuration in the same change.

  3. Avoid changing the connector id unless you intend to. Dex treats a changed id as a removal of the old connector plus an addition of a new one: tokens issued through the old id can no longer be refreshed, and in multi-tenant deployments the Tenant scoping of the connector may change. The name field is display-only and safe to change at any time.

  4. Continue with Apply the Configuration.

Remove a Connector

  1. Delete the connector entry from the dex.config.connectors list. Leave the remaining connectors in the list unchanged.

  2. Confirm that at least one sign-in method remains. If you remove all connectors and local Dex users are disabled or have no entries under dex.config.staticPasswords, no one can sign in to PaletteAI. Refer to Local Dex Users for details on local users.

  3. Optionally, delete the corresponding client registration on the identity provider so the credentials cannot be reused.

  4. Continue with Apply the Configuration. Removing a connector does not immediately sign out its users. Refer to Effect on Active Sessions.

Scope Connectors per Tenant

If each Tenant has its own subdomain, you can name Dex connectors <prefix>_<subdomain> so each Tenant's sign-in page lists only the providers that belong to that Tenant. The convention applies to any Dex connector type; the examples in this section use Keycloak and GitHub.

When the sign-in page loads, PaletteAI takes the first DNS label of the request hostname, converts it to lowercase, and uses it as the normalized Tenant subdomain. For example, https://Tenant-1.example.com normalizes to tenant-1. It then compares this value against each connector's id, with both sides in lowercase:

  • A connector id with no underscore is global and appears on every Tenant subdomain.

  • A connector id with an underscore (<prefix>_<suffix>) is Tenant-scoped. It appears only when <suffix> matches the normalized Tenant subdomain. The prefix cannot be empty.

The following table shows visibility for a request to https://tenant-1.example.com. The github row applies to every Tenant subdomain.

Connector idVisible on tenant-1?Reason
githubYesNo underscore, treated as global.
keycloak_tenant-1YesSuffix matches the Tenant subdomain.
okta_tenant-2NoSuffix matches a different subdomain.
_tenant-1NoEmpty prefix; the rule requires a prefix.
info

The filter looks only at the connector id. The redirectURI, name, and type fields have no effect on visibility.

To apply the convention, define one connector per Tenant. The following example shows two Tenant-scoped Keycloak connectors and one shared GitHub connector.

dex:
config:
connectors:
- type: github
id: github
name: GitHub
config:
clientID: <github-client-id>
clientSecret: <github-client-secret>
redirectURI: https://<your-paletteai-domain>/dex/callback
- type: oidc
id: keycloak_tenant-1
name: Keycloak (Tenant 1)
config:
issuer: https://keycloak.example.com/realms/tenant-1
clientID: dex
clientSecret: <keycloak-tenant-1-client-secret>
redirectURI: https://tenant-1.example.com/dex/callback
- type: oidc
id: keycloak_tenant-2
name: Keycloak (Tenant 2)
config:
issuer: https://keycloak.example.com/realms/tenant-2
clientID: dex
clientSecret: <keycloak-tenant-2-client-secret>
redirectURI: https://tenant-2.example.com/dex/callback

Each Tenant-scoped connector sets redirectURI to its Tenant's public URL. Most identity providers require redirectURI to match an entry already registered with the provider. This redirect-URL check happens on the provider and is separate from the PaletteAI filter, which only checks the connector id.

After you complete Apply the Configuration, open the sign-in page on each Tenant's public hostname and confirm that only the global connectors and the matching Tenant-scoped connector appear. To check from the logs, run:

kubectl logs --namespace <namespace> --selector app.kubernetes.io/name=canvas --tail=50

When the filter finds matching connectors, the PaletteAI UI log records Number of OIDC connectors for this host: followed by the count. When no connector matches, the log records OIDC connectors are configured but none match this request host.

Troubleshoot Tenant-Scoped Connectors

If a Tenant-scoped connector does not appear on its Tenant subdomain, or appears on the wrong subdomain, check the following:

  • The user receives No valid provider was selected. The user selected a connector that is not in the filtered list for the current Tenant subdomain. Check that the suffix of the connector id matches the first DNS label of the public hostname. The match is case-insensitive, so keycloak_Tenant-1 and keycloak_tenant-1 are interchangeable, but keycloak_tenant1 does not match tenant-1.example.com. Also check that DNS resolves the Tenant subdomain to your ingress.

  • The connector appears on every subdomain. The connector id has no underscore, so PaletteAI treats it as global. Rename the id to <prefix>_<subdomain>, then complete Apply the Configuration.

  • The connector never appears. The connector id starts with _ (empty prefix), or the suffix matches no Tenant subdomain. Add a non-empty prefix and check that the suffix matches the first DNS label of a Tenant hostname.

Apply the Configuration

Helm-Based Installations

Apply the updated values with Helm. Adjust the namespace and values file path if your installation uses different ones.

helm upgrade mural oci://public.ecr.aws/mural/mural --version 1.1.6 \
--namespace mural-system --values values.yaml --wait

If Flux manages your PaletteAI installation, update the values in the mural HelmRelease instead and let Flux reconcile the release. Refer to Upgrade with Flux for the resource layout.

Appliance Installations

For appliance-based installations, edit the mural HelmRelease directly. The values.yaml file on the appliance nodes is only used during the initial installation.

kubectl edit helmrelease mural --namespace mural-system

Update the connector list under spec.values.dex.config.connectors, then save and exit. Flux reconciles the release and applies the change. Refer to Update Values After Installation for the full workflow.

Restart the Affected Deployments

After the Helm release is updated, restart Dex and the PaletteAI UI so both pick up the new connector configuration, and wait for the rollouts to finish.

kubectl rollout restart deployment dex --namespace <namespace>
kubectl rollout restart deployment canvas --namespace <namespace>
kubectl rollout status deployment dex --namespace <namespace>
kubectl rollout status deployment canvas --namespace <namespace>

Effect on Active Sessions

Connector changes do not terminate active sessions immediately. The PaletteAI UI keeps users signed in by refreshing their tokens through Dex shortly before each token expires. The default token lifetime is eight hours, set by dex.config.expiry.idTokens.

  • Removed connector, or changed connector id. Users who signed in through the connector stay signed in until their current token approaches expiry. The next token refresh fails because the connector no longer exists, and the user is redirected to the sign-in page.

  • Updated connector. Sessions usually continue uninterrupted. If the update invalidates the upstream relationship — for example, the client registration was deleted or its secret rotated on the provider side — the next token refresh fails and the user must sign in again.

To revoke sessions immediately instead of waiting for token expiry, delete the Dex refresh tokens for the affected users. Dex stores them as custom resources in the dex.coreos.com API group in the PaletteAI installation namespace; each resource records the connector id and the user identity it was issued for.

kubectl get refreshtokens.dex.coreos.com --namespace <namespace>
kubectl delete refreshtokens.dex.coreos.com <resource-name> --namespace <namespace>

Validate

  1. Confirm that the dex and canvas pods restarted and are in a Running state.

    kubectl get pods --namespace <namespace> --selector app.kubernetes.io/name=dex
    kubectl get pods --namespace <namespace> --selector app.kubernetes.io/name=canvas
  2. Check the Dex logs for configuration errors. Dex validates its configuration at startup, and a malformed connector entry prevents the pod from becoming ready.

    kubectl logs --namespace <namespace> --selector app.kubernetes.io/name=dex --tail=50
  3. Open the PaletteAI sign-in page and confirm that the connector list matches your change: an added connector appears, a removed connector is gone, and a renamed connector shows its new display name. In multi-tenant deployments, check each affected Tenant subdomain. To confirm from the logs, check the PaletteAI UI log for the Number of OIDC connectors for this host: entry.

    kubectl logs --namespace <namespace> --selector app.kubernetes.io/name=canvas --tail=50
  4. Sign in through the added or updated connector and confirm that you land in PaletteAI. If the connector forwards group claims, confirm that they arrived by checking the Dex logs for a groups=[...] entry.

  5. After removing a connector, sign in through one of the remaining sign-in methods to confirm that authentication still works.

Next Steps

Connectors only control how users sign in. To control what each authenticated user can do, configure per-user RBAC through Configure Kubernetes API Server to Trust OIDC Provider or Configure User Impersonation. When you add a connector that forwards new groups, remember to extend your group mappings and role bindings to cover them.