Skip to content
Integrations

Pre-1.0 · Design-partner program

Argo CD sign-in through Nauthera.

Argo CD SSO through Nauthera: a public OIDCClient with PKCE, the argocd-cm and argocd-rbac-cm settings, CLI login, roles by email and common errors.

By Michael Beutler, FounderPublished

Argo CD signs people in through any OpenID Connect provider set in its argocd-cm ConfigMap, without Dex. With Nauthera the client is an OIDCClient in the argocd namespace, a public client with PKCE, so there is no client secret to deliver: the web UI and the argocd CLI share it. Roles map by email, since Nauthera emits no groups claim.

Checked against: Argo CD 3.6.0 (released November 3, 2026), its user management docs, RBAC docs and OIDC client code at that tag, read on November 4, 2026, and the OIDCClient definition in nauthera-server. This page has not recorded an end-to-end test against a running Argo CD.

1. Admit the namespace

The client configures the organization that admits the argocd namespace. For the main organization that is the chart value operator.mainOrganizationNamespaces, empty by default:

# nauthera-server chart values
operator:
  enabled: true
  mainOrganizationNamespaces: [argocd]

For another organization, add argocd to its Organization resource's spec.namespaces; its issuer is then https://auth.example.com/orgs/<slug>.

2. The OIDCClient

apiVersion: nauthera.io/v1alpha1
kind: OIDCClient
metadata:
  name: argocd
  namespace: argocd
spec:
  clientId: argocd
  displayName: Argo CD
  redirectUris:
    - https://argocd.example.com/auth/callback   # the web UI
    - http://localhost:8085/auth/callback        # argocd login --sso
  postLogoutRedirectUris:
    - https://argocd.example.com
  grantTypes: [authorization_code, refresh_token]
  responseTypes: [code]
  scopes: [openid, profile, email, offline_access]
  tokenEndpointAuthMethod: none
  pkcePolicy: required_s256
  allowRefresh: true
  deletionPolicy: Retain

tokenEndpointAuthMethod: none makes it a public client, which must use required_s256. Nauthera matches redirect URIs exactly, so each one Argo CD sends is listed: its url plus /auth/callback, and the CLI's loopback address on its default --sso-port of 8085. Argo CD's Keycloak guide also lists /pkce/verify; in 3.6.0 the server runs the PKCE exchange itself and returns to /auth/callback, and the web UI has no /pkce/verify route (UI routes).

3. argocd-cm

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: Nauthera
    issuer: https://auth.example.com
    clientID: argocd
    enablePKCEAuthentication: true
    requestedScopes: ["openid", "profile", "email", "offline_access"]
    refreshTokenThreshold: 2m
    logoutURL: https://auth.example.com/end_session?client_id=argocd&id_token_hint={{token}}&post_logout_redirect_uri={{logoutRedirectURL}}
  • requestedScopes must be set. Argo CD asks for groups by default, and Nauthera refuses a scope the client is not registered for with invalid_scope.
  • refreshTokenThreshold keeps a session alive. Argo CD's session lasts as long as the ID token, and Nauthera's ID tokens last 10 minutes by default (issuer.id_token_ttl). With offline_access and allowRefresh, Argo CD refreshes the token this long before it expires.
  • logoutURL ends the Nauthera session too. Argo CD fills in its url, without a trailing slash, which is why postLogoutRedirectUris lists it that way. When the ID token in the hint has expired, Nauthera asks the user to confirm before signing out.
  • rootCA: add the PEM of your CA here when Nauthera's certificate is not from a public one, as in a closed network.

4. Roles: argocd-rbac-cm

Nauthera's tokens carry no groups claim, so bind roles to email addresses. scopes tells Argo CD which claims to match against policy subjects, in addition to sub:

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
  labels:
    app.kubernetes.io/name: argocd-rbac-cm
    app.kubernetes.io/part-of: argocd
data:
  scopes: "[email]"
  policy.csv: |
    g, alice@example.com, role:admin
    g, bob@example.com, role:readonly

Without policy.default, a signed-in user no line names sees no applications. Bind by email only where addresses are trustworthy: self-registration is off by default (auth.registration.enabled), and where it is on, require a verified address before a session starts: config.orgs.main.email_verification_required in the chart for the main organization, spec.emailVerificationRequired on an Organization. Binding by sub instead is stable but less readable.

5. The CLI

argocd login argocd.example.com --sso

The CLI opens the browser on Nauthera's sign-in page, runs the authorization code flow with PKCE against the same client, and receives the code on http://localhost:8085. For another port, pass --sso-port and register that redirect URI too. Nauthera asks for consent on every sign-in through a loopback redirect, whoever registered the client, because another program on the machine could listen on the same port. Sign-ins through the web UI are not asked: an operator-registered client counts as approved by an administrator.

Why not a confidential client and its Secret

The operator could generate a client secret, but Argo CD reads a $<secret>:<key> reference only from a Secret labelled app.kubernetes.io/part-of: argocd, and the operator labels the Secret it writes only with app.kubernetes.io/managed-by. A label you add by hand survives the operator's updates, which change only the data and the fingerprint annotation, but not a rotation: deleting the Secret to rotate it makes the operator write a new one without the label. With PKCE, the public client needs no secret.

When something goes wrong

What you seeWhyFix
The OIDCClient shows NamespaceNotAdmittedNo organization admits argocdStep 1
Nauthera answers invalid_scopeArgo CD's default scopes include groupsSet requestedScopes
Nauthera refuses the redirect_uriIt differs from every registered URI, character for characterMake url and redirectUris agree; register the CLI's port
Users sign in but see no applicationsNo policy line names themAdd their email to policy.csv, with scopes: "[email]"
Users are signed out after about ten minutesThe ID token expired and was not refreshedoffline_access, allowRefresh and refreshTokenThreshold
x509: certificate signed by unknown authorityNauthera's certificate is from a private CArootCA in oidc.config; for the CLI, see Argo CD's FAQ
Logout ends on Nauthera's own pagepost_logout_redirect_uri is not registered exactlyList url without a trailing slash in postLogoutRedirectUris

Argo CD has no health check of its own for an OIDCClient, so it gives the resource no health status and leaves it out of the application's health, whatever the operator reports (health code). The GitOps guide has the health check that reads the operator's status instead.

Release updates

Hear when the operator ships

One email when the operator ships. No newsletter.

By joining, you agree to our Privacy Policy and Terms.

Design partners

Apply for a design-partner seat

Five teams get calls with the founder, a say in the operator's design, and direct support when they pilot it.

Optional

We store your answers with your email address to select design partners. Privacy Policy