Argo CD’s Single Sign-On (SSO) setup with Dex as an OIDC provider and Okta as the upstream identity provider is surprisingly resilient once you understand the handshake. The core idea is that Okta authenticates the user, Dex acts as an intermediary translating Okta’s SAML/OIDC claims into OIDC for Argo CD, and Argo CD trusts Dex.

Let’s see this in action. Imagine a user, Alice, wants to access Argo CD.

  1. Alice navigates to the Argo CD UI. Argo CD, configured to use Dex for OIDC, redirects Alice’s browser to Dex’s login page.
  2. Dex, configured to use Okta as an upstream OIDC provider, redirects Alice’s browser to Okta’s login page.
  3. Alice logs into Okta with her Okta credentials.
  4. Okta successfully authenticates Alice and, based on the configured application, issues an ID token and access token back to Dex.
  5. Dex receives these tokens from Okta, validates them, and then issues its own OIDC tokens (ID token, access token, refresh token) back to Alice’s browser. These tokens contain claims about Alice, translated from Okta’s claims.
  6. Alice’s browser presents Dex’s tokens to Argo CD.
  7. Argo CD validates Dex’s tokens. If valid, Argo CD uses the claims (like username and groups) within the token to determine Alice’s access level and logs her in.

This flow relies on a few key components: Okta’s OIDC application configuration, Dex’s OIDC provider configuration for Okta, and Argo CD’s OIDC configuration for Dex.

Okta Configuration

First, you need an OIDC application in Okta.

  • Create an OIDC Application: In Okta, go to "Applications" > "Applications list" > "Create App Integration." Choose "OIDC – OpenID Connect" and "Web Application."
  • General Settings: Give it a name like "ArgoCD Dex Connector."
  • Grant Type: Ensure "Implicit (hybrid)" is checked, as Dex will use this.
  • Sign-in redirect URIs: This is crucial. You’ll need the URL for Dex’s OIDC callback. It typically looks like http://<dex-service-host>:<dex-service-port>/callback. If Dex is running via Kubernetes and exposed via a service, this might be http://dex.argocd.svc.cluster.local/callback (for internal cluster access) or http://dex.example.com/callback (if exposed externally).
  • Save: After saving, Okta will provide you with a Client ID and a Client Secret. Treat the Client Secret like a password. You’ll also need Okta’s Issuer URL (e.g., https://<your-okta-domain>.okta.com/oauth2/<your-auth-server-id>).

Dex Configuration

Dex acts as the bridge. You’ll typically configure this in Dex’s config.yaml file.

issuer: http://dex.example.com:5556 # The issuer URL for Dex itself
connectors:
- type: oidc
  id: okta
  name: Okta
  config:
    client_id: <your-okta-client-id>
    client_secret: <your-okta-client-secret>
    issuer: <your-okta-issuer-url>
    # If Okta uses a custom domain and you need to bypass cert verification (not recommended for prod)
    # insecure_skip_verify: true
    # If you need to scope down what Dex requests from Okta (e.g., just profile and email)
    # scopes: ["openid", "profile", "email"]
    # If Okta's groups are not directly in the ID token, but in a separate endpoint
    # user_info_url: <your-okta-issuer-url>/v1/userinfo
    # If Okta groups are not directly mapped, you might need to specify how to extract them.
    # This is highly dependent on Okta's configuration.
    # For instance, if groups are in a custom claim like 'groups':
    # group_claim: groups
  • issuer (Dex): This is the URL Argo CD will use to talk to Dex.
  • client_id / client_secret (Okta): The credentials Okta gave you for the OIDC app.
  • issuer (Okta): The issuer URL of your Okta OIDC application.
  • redirect_uri (implicit): Dex automatically registers http://<dex-host>:<dex-port>/callback with Okta based on its own issuer and the connector configuration. Make sure this matches what you put in Okta.

Argo CD Configuration

Finally, you tell Argo CD to use Dex. This is done via the argocd-cm ConfigMap.

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  oidc.config: |
    name: Dex
    # The issuer URL for Dex. This MUST match the 'issuer' field in Dex's config.yaml
    issuer: http://dex.example.com:5556
    # The client ID that Argo CD will use when talking to Dex. Dex will issue this to Argo CD.
    # For Dex, this is usually derived from its own server config, not explicitly set here.
    # If Dex needs a specific client ID for Argo CD, you'd configure that in Dex's `staticClients` section.
    # For simplicity, we assume Dex is configured to accept any client with a valid request.
    # If using staticClients in Dex:
    # client_id: argocd-oidc-client # This value must match your staticClients entry in Dex
    # If you need to map specific claims from Dex's OIDC tokens to Argo CD roles (e.g., 'groups'):
    # ssl_insecure_skip_verify: false # Set to true if Dex uses a self-signed cert and you can't configure trust
    # root_certs: |
    #   -----BEGIN CERTIFICATE-----
    #   ... your Dex CA cert ...
    #   -----END CERTIFICATE-----
    # The default scopes Argo CD requests from Dex. 'groups' is crucial for RBAC.
    # If Dex is configured to get groups from Okta, ensure 'groups' is requested and available.
    requested_scopes: '[openid, profile, email, groups]'
  # This section maps groups from the OIDC token to Argo CD roles.
  # 'groups' is the claim name from Dex's token.
  # 'admin', 'member', 'readonly' are Argo CD roles.
  oidc.provider.dex.extra.scopes: '[openid, profile, email, groups]' # Redundant if in oidc.config, but good practice
  oidc.provider.dex.groups_claim: 'groups' # The claim in Dex's token that contains group information
  oidc.provider.dex.groups_roles: |
    admin:
    - "argocd-admins" # Okta group name that maps to Argo CD admins
    member:
    - "argocd-developers" # Okta group name that maps to Argo CD members
    readonly:
    - "argocd-viewers" # Okta group name that maps to Argo CD readonly users

  • oidc.config: Defines the OIDC provider.
    • name: A friendly name.
    • issuer: The URL of your Dex server.
    • requested_scopes: What information Argo CD asks Dex for. groups is vital for role-based access control.
  • oidc.provider.dex.groups_claim: Tells Argo CD which claim in the OIDC token contains the user’s group memberships. This must match what Dex is configured to pass from Okta.
  • oidc.provider.dex.groups_roles: This is where you map the group names (as provided by Dex/Okta) to specific Argo CD roles.

The Counter-Intuitive Part

The most common point of failure, and what most people don’t immediately grasp, is that the groups claim Argo CD expects must originate from Okta and be passed through Dex. If Okta doesn’t include group information in its OIDC tokens, or if Dex is not configured to request and propagate those groups, Argo CD will never see them, and your groups_roles mapping will appear to do nothing. You’ll need to inspect the token claims (using tools like jwt.io or by enabling debug logging in Dex) to ensure the groups claim is present and populated correctly. Often, this requires configuring Okta to include group memberships in the access_token or id_token via custom authorization server policies or scopes.

Once these pieces are in place, you’ll be able to log into Argo CD using your Okta credentials, with your access level determined by your Okta group memberships. The next hurdle you’ll likely encounter is fine-tuning the specific group names and roles to match your organization’s security policies.

Want structured learning?

Take the full Argocd course →