Skip to main content

Overview

Argo CD supports SSO authentication through two methods:
  1. Bundled Dex OIDC provider: Use when your provider doesn’t support OIDC (SAML, LDAP) or to leverage Dex connector features
  2. External OIDC provider: Use with existing OIDC providers like Okta, Auth0, Keycloak, Google, or Microsoft
SSO requires configuring the url field in the argocd-cm ConfigMap. This is the externally-facing base URL of your Argo CD instance.

Dex Configuration

Argo CD embeds Dex for delegating authentication to external identity providers.

GitHub OAuth2 Example

First, register an OAuth application in GitHub with the callback URL: https://argocd.example.com/api/dex/callback Then configure the argocd-cm ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
  labels:
    app.kubernetes.io/name: argocd-cm
    app.kubernetes.io/part-of: argocd
data:
  url: https://argocd.example.com
  
  dex.config: |
    connectors:
      - type: github
        id: github
        name: GitHub
        config:
          clientID: aabbccddeeff00112233
          clientSecret: $dex.github.clientSecret
          orgs:
          - name: your-github-org
            teams:
            - red-team
Dex will automatically use the correct redirectURI to match your Argo CD URL. No need to set it explicitly.

GitHub Enterprise

data:
  url: https://argocd.example.com
  
  dex.config: |
    connectors:
      - type: github
        id: acme-github
        name: Acme GitHub
        config:
          hostName: github.acme.example.com
          clientID: abcdefghijklmnopqrst
          clientSecret: $dex.acme.clientSecret
          orgs:
          - name: your-github-org

Secret References

By default, secrets like $dex.github.clientSecret are looked up in the argocd-secret Secret. To use a different Secret:
clientSecret: $my-k8s-secret:dex.github.clientSecret
Custom Secrets must have the label app.kubernetes.io/part-of: argocd.

OIDC Configuration with Dex

Use Dex as an OIDC intermediary to fetch information from the UserInfo endpoint:
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  url: https://argocd.example.com
  
  dex.config: |
    connectors:
      - type: oidc
        id: oidc
        name: OIDC
        config:
          issuer: https://example-oidc-provider.example.com
          clientID: aaaabbbbccccddddeee
          clientSecret: $dex.oidc.clientSecret

Requesting Additional Claims

Request additional scopes like groups:
dex.config: |
  connectors:
    - type: oidc
      id: oidc
      name: OIDC
      config:
        issuer: https://example-oidc-provider.example.com
        clientID: aaaabbbbccccddddeee
        clientSecret: $dex.oidc.clientSecret
        insecureEnableGroups: true
        scopes:
        - profile
        - email
        - groups
Group information is only refreshed at authentication time. Changes to group membership won’t take effect until users re-authenticate.

Using UserInfo Endpoint

When claims aren’t available in the ID token, retrieve them from the UserInfo endpoint:
dex.config: |
  connectors:
    - type: oidc
      id: oidc
      name: OIDC
      config:
        issuer: https://example-oidc-provider.example.com
        clientID: aaaabbbbccccddddeee
        clientSecret: $dex.oidc.clientSecret
        getUserInfo: true
        insecureEnableGroups: true
        scopes:
        - profile
        - email
        - groups

Direct OIDC Configuration

Connect directly to an OIDC provider without Dex:
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
  labels:
    app.kubernetes.io/name: argocd-cm
    app.kubernetes.io/part-of: argocd
data:
  url: https://argocd.example.com
  
  oidc.config: |
    name: Okta
    issuer: https://dev-123456.oktapreview.com
    clientID: aaaabbbbccccddddeee
    clientSecret: $oidc.okta.clientSecret
    # Optional: customize requested scopes
    requestedScopes: ["openid", "profile", "email", "groups"]
    # Optional: request specific ID token claims
    requestedIDTokenClaims:
      groups:
        essential: true

TLS Configuration

data:
  # Skip certificate verification (not recommended for production)
  oidc.tls.insecure.skip.verify: "false"
Only set oidc.tls.insecure.skip.verify to true if you understand the security risks.

RBAC with SSO

Configure which OIDC scopes to use for RBAC:
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.csv: |
    p, my-org:team-alpha, applications, sync, my-project/*, allow
    g, my-org:team-beta, role:admin
    g, user@example.org, role:admin
  
  policy.default: role:readonly
  scopes: '[groups, email]'
The scopes field specifies which OIDC claims to examine for RBAC (defaults to [groups]).

Session Configuration

Configure session duration and behavior:
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  # Specifies token expiration duration
  users.session.duration: "24h"
  
  # Enable anonymous access (uses policy.default)
  users.anonymous.enabled: "false"

Multiple Base URLs

Support multiple URLs for Argo CD access:
data:
  url: https://argocd.example.com
  additionalUrls: |
    - https://argocd-secondary.example.com
    - https://cd.example.org

Dex Static Clients

Reuse Dex with other services:
data:
  dex.config: |
    connectors:
      - type: github
        id: github
        name: GitHub
        config:
          clientID: aabbccddeeff00112233
          clientSecret: $dex.github.clientSecret
          orgs:
          - name: your-github-org
    
    staticClients:
    - id: argo-workflow
      name: Argo Workflow
      redirectURIs:
      - https://argo-workflows.example.com/oauth2/callback
      secret: $workflows.dex.clientSecret

Provider-Specific Examples

Okta

oidc.config: |
  name: Okta
  issuer: https://dev-123456.okta.com
  clientID: 0oaabbbcccdddeeefff
  clientSecret: $oidc.okta.clientSecret
  requestedScopes:
  - openid
  - profile
  - email
  - groups

Google (G Suite)

Using Dex:
dex.config: |
  connectors:
  - type: google
    id: google
    name: Google
    config:
      clientID: xxxxxxxxxxxx.apps.googleusercontent.com
      clientSecret: $dex.google.clientSecret
      hostedDomains:
      - example.com
      serviceAccountFilePath: /path/to/service-account.json

Auth0

oidc.config: |
  name: Auth0
  issuer: https://example.auth0.com/
  clientID: aabbccddeeff00112233
  clientSecret: $oidc.auth0.clientSecret

Keycloak

oidc.config: |
  name: Keycloak
  issuer: https://keycloak.example.com/realms/master
  clientID: argocd
  clientSecret: $oidc.keycloak.clientSecret
  requestedScopes:
  - openid
  - profile
  - email
  - groups

Microsoft Azure AD

dex.config: |
  connectors:
  - type: microsoft
    id: microsoft
    name: Microsoft
    config:
      clientID: aaaabbbbccccddddeeee
      clientSecret: $dex.microsoft.clientSecret
      tenant: your-tenant-id
      redirectURI: https://argocd.example.com/api/dex/callback

Disabling Admin User

Once SSO is configured, disable the built-in admin user:
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  admin.enabled: "false"
Ensure you have configured at least one user with admin privileges via RBAC before disabling the admin user.

Adding Local Users

Create additional local users in the argocd-cm ConfigMap:
data:
  accounts.alice: apiKey, login
  accounts.bob: apiKey
  accounts.alice.enabled: "true"
Capabilities:
  • apiKey: Allows generating API keys
  • login: Allows UI login

Failed Login Rate Limiting

Configure via environment variables on the argocd-server deployment:
  • ARGOCD_SESSION_FAILURE_MAX_FAIL_COUNT: Max failed logins (default: 5)
  • ARGOCD_SESSION_FAILURE_WINDOW_SECONDS: Failure window duration (default: 300)
  • ARGOCD_SESSION_MAX_CACHE_SIZE: Max cache entries (default: 1000)
  • ARGOCD_MAX_CONCURRENT_LOGIN_REQUESTS_COUNT: Max concurrent logins (default: 50)

Complete Example

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
  labels:
    app.kubernetes.io/name: argocd-cm
    app.kubernetes.io/part-of: argocd
data:
  url: https://argocd.example.com
  
  users.session.duration: "24h"
  users.anonymous.enabled: "false"
  
  admin.enabled: "false"
  
  accounts.devops: apiKey, login
  
  dex.config: |
    connectors:
      - type: github
        id: github
        name: GitHub
        config:
          clientID: aabbccddeeff00112233
          clientSecret: $dex.github.clientSecret
          orgs:
          - name: your-org
            teams:
            - devops-team
            - platform-team
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.csv: |
    g, your-org:devops-team, role:admin
    p, your-org:platform-team, applications, *, */*, allow
    p, your-org:platform-team, repositories, *, *, allow
  
  policy.default: role:readonly
  scopes: '[groups]'

Best Practices

Use SSO for Teams

Implement SSO with group-based access control instead of managing individual local users.

Secure Secrets

Store sensitive values like client secrets in Kubernetes Secrets, not directly in ConfigMaps.

Session Duration

Set appropriate session durations based on your security requirements.

Disable Admin

Disable the built-in admin user once SSO and RBAC are properly configured.