1559 words
8 minutes
Integrating Keycloak with ArgoCD — Single Sign-On via OpenID Connect

This guide walks you through integrating ArgoCD with Keycloak as a Single Sign-On (SSO) Identity Provider using ArgoCD’s native OpenID Connect (OIDC) support — no Dex required. Along the way, we’ll map Keycloak groups to ArgoCD RBAC roles for fine-grained access control.

This document focuses purely on the integration itself. For the Keycloak installation, refer to the separate guide: Deploying Keycloak 26 in Production on AlmaLinux 9.

Placeholders used throughout this guide: Wherever you see values like sso.example.com, argocd.example.com, or YOUR_CLIENT_SECRET, replace them with your own actual values.

PlaceholderDescriptionExample
sso.example.comYour Keycloak FQDNsso.company.net
argocd.example.comYour ArgoCD FQDNargocd.company.net
YOUR_CLIENT_SECRETThe OIDC client secret from KeycloakCopy from the Credentials tab
YOUR_REALMYour Keycloak realm nameinternal

Table of Contents#

  1. Prerequisites
  2. Why Native OIDC Instead of Dex
  3. Create a Client for ArgoCD in Keycloak
  4. Add a Groups Mapper
  5. Create Groups in Keycloak
  6. Store the Client Secret in a Kubernetes Secret
  7. Configure argocd-cm
  8. Configure argocd-rbac-cm
  9. Restart & Test Login
  10. Break-Glass Account (Local Admin)
  11. Offboarding
  12. Troubleshooting

1. Prerequisites#

  • Keycloak is up and running, accessible over HTTPS (e.g., https://sso.example.com), with a realm already created (see the GitLab integration guide for realm creation steps).
  • ArgoCD is installed on your Kubernetes cluster and accessible over HTTPS (e.g., https://argocd.example.com).
  • Admin access to the Keycloak Admin Console.
  • kubectl access with edit permissions on the namespace where ArgoCD is running (e.g., argocd).

2. Why Native OIDC Instead of Dex#

ArgoCD supports two approaches for enabling SSO:

  • Dex — a built-in authentication proxy that can aggregate multiple identity providers (LDAP, GitHub, SAML, OIDC, etc.) into a single configuration.
  • Native OIDC (oidc.config directly in argocd-cm) — ArgoCD communicates directly with the Identity Provider without an intermediary.

Since Keycloak already supports OIDC natively and is the only Identity Provider in use, native OIDC is the simpler choice — there’s no need to run an additional Dex component in the cluster, which means fewer moving parts and fewer points of failure. Dex only becomes relevant if you need to aggregate multiple Identity Providers simultaneously.


3. Create a Client for ArgoCD in Keycloak#

  1. Log in to https://sso.example.com/admin/ and switch to your realm (e.g., YOUR_REALM).
  2. Navigate to ClientsCreate client.
  3. General Settings
    • Client type: OpenID Connect
    • Client ID: argocd
    • Click Next.
  4. Capability config
    • Client authentication: On
    • Authentication flow: check Standard flow only.
    • Click Next, then Save.
  5. On the Settings page:
    • Valid redirect URIs: https://argocd.example.com/auth/callback
    • Valid post logout redirect URIs: https://argocd.example.com/*
    • Web origins: https://argocd.example.com
  6. Click Save.
  7. Open the Credentials tab and copy the Client secret — you’ll need it in step 6.

4. Add a Groups Mapper#

By default, the groups claim is not automatically included in Keycloak’s OIDC tokens. ArgoCD needs this claim to match users to RBAC roles, so it must be added manually.

  1. In your realm, navigate to Client scopesCreate client scope.
    • Name: groups
    • Type: Default (not Optional — this ensures the groups claim is always included in tokens without the client needing to explicitly request it)
    • Click Save.

The "groups" client scope created as a Default scope in Keycloak's Client Scopes list.

  1. Enter the newly created groups client scope → Mappers tab → Add mapperBy configurationGroup Membership.
    • Name: groups
    • Token Claim Name: groups
    • Full group path: Off (so the output is a plain group name like argocd-admins rather than /argocd-admins with the full path)
    • Add to ID token: On
    • Add to access token: On
    • Click Save.
  2. Go back to the argocd client → Client scopes tab → verify that the groups scope is already assigned (since it was created as a Default scope, it should automatically appear for all clients).

5. Create Groups in Keycloak#

Create the groups that will be mapped to ArgoCD roles. Here’s an example with three access tiers:

  1. Navigate to GroupsCreate group, and create three groups:
    • argocd-admins
    • argocd-developers
    • argocd-viewers

The three ArgoCD groups (argocd-admins, argocd-developers, argocd-viewers) created in Keycloak's Groups section.

  1. Assign users to the appropriate groups via Users → select a user → Groups tab → Join group.

6. Store the Client Secret in a Kubernetes Secret#

The client secret should never be written as plain text in a ConfigMap. Instead, store it in the argocd-secret Secret that ArgoCD already uses:

Terminal window
kubectl -n argocd patch secret argocd-secret \
-p '{"stringData": {"oidc.keycloak.clientSecret": "YOUR_CLIENT_SECRET"}}'

7. Configure argocd-cm#

Edit the argocd-cm ConfigMap:

Terminal window
kubectl -n argocd edit configmap argocd-cm

Add or ensure the data section contains:

apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
url: https://argocd.example.com
oidc.config: |
name: Keycloak
issuer: https://sso.example.com/realms/YOUR_REALM
clientID: argocd
clientSecret: $oidc.keycloak.clientSecret
requestedScopes:
- openid
- profile
- email
- groups
requestedIDTokenClaims:
groups:
essential: true

Key notes:

  • clientSecret: $oidc.keycloak.clientSecret — the $key syntax tells ArgoCD to read the value from the argocd-secret Secret (stored in step 6), rather than from plain text in the ConfigMap.
  • requestedScopes must include groups, matching the client scope created in step 4.

If ArgoCD is managed via a Helm chart (rather than manual kubectl edit), the same configuration can be placed in values.yaml:

configs:
cm:
url: https://argocd.example.com
oidc.config: |
name: Keycloak
issuer: https://sso.example.com/realms/YOUR_REALM
clientID: argocd
clientSecret: $oidc.keycloak.clientSecret
requestedScopes: ["openid", "profile", "email", "groups"]
requestedIDTokenClaims:
groups:
essential: true

8. Configure argocd-rbac-cm#

Edit the argocd-rbac-cm ConfigMap to map Keycloak groups to ArgoCD roles:

Terminal window
kubectl -n argocd edit configmap argocd-rbac-cm
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argocd
data:
policy.default: role:readonly
scopes: '[groups]'
policy.csv: |
# "argocd-admins" group gets full admin access
g, argocd-admins, role:admin
# "argocd-developers" group can deploy to non-prod environments
p, role:developer, applications, get, */*, allow
p, role:developer, applications, sync, dev/*, allow
p, role:developer, applications, sync, staging/*, allow
p, role:developer, applications, create, dev/*, allow
p, role:developer, applications, delete, dev/*, allow
g, argocd-developers, role:developer
# "argocd-viewers" group is read-only
g, argocd-viewers, role:readonly

Important notes:

  • scopes: '[groups]' is required — this tells ArgoCD to read the groups claim from the token when evaluating policies. Without this line, the mapping g, argocd-admins, role:admin will never match, even if the groups claim is present in the token.
  • policy.default: role:readonly — the default role for users who successfully log in via SSO but don’t belong to any group. You can set this to an empty string ("") if you want users without a group assignment to have no access at all.

9. Restart & Test Login#

Apply the changes by restarting argocd-server:

Terminal window
kubectl -n argocd rollout restart deployment argocd-server

Wait for the rollout to complete:

Terminal window
kubectl -n argocd rollout status deployment argocd-server

Open https://argocd.example.com and click the “LOG IN VIA KEYCLOAK” button (the label matches the name defined in oidc.config). After successfully authenticating through Keycloak, verify that you have the expected access level based on the group assigned in step 5.

The ArgoCD login page showing the "LOG IN VIA KEYCLOAK" button after successful OIDC configuration.

Optionally, verify the assigned role via the CLI (if the argocd CLI is installed):

Terminal window
argocd login argocd.example.com --sso
argocd account get-user-info

10. Break-Glass Account (Local Admin)#

ArgoCD ships with a built-in local admin account (its initial password is auto-generated and stored in the argocd-initial-admin-secret Secret). Instead of deleting it, keep it as an emergency access path — similar to the break-glass pattern used in the GitLab integration.

Retrieve the initial password (if you haven’t already):

Terminal window
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d

Recommendations:

  • Log in once as admin, change the password to a very strong one, and store it in a password manager.
  • Do not delete this admin account — keep it active but guard the credentials carefully. Only use it if Keycloak goes down and no OIDC users can log in.
  • For extra protection, the admin account can be temporarily disabled via accounts.admin.enabled: "false" in argocd-cm after confirming that at least one OIDC group has a working role:admin assignment — but make sure you have a way to re-enable it (via kubectl edit directly against the cluster) before doing this.

11. Offboarding#

Unlike GitLab (which requires two separate steps due to account linking), ArgoCD does not store local accounts for OIDC users — access is entirely derived from the groups claim in the token each time a user logs in or re-authenticates. The implications:

  • Remove the user from their group in Keycloak (or disable/delete the user) — ArgoCD access is automatically revoked the next time the token or session is refreshed, with no additional steps needed on the ArgoCD side.
  • Active sessions will continue to follow the validity of the already-issued token (requestedIDTokenClaims, Keycloak’s default token expiry). If you need immediate revocation, revoke the user’s session directly from Keycloak (Users → select user → Sessions tab → Sign out), rather than just removing them from the group.

This is one of the key advantages of group-based RBAC over account linking: there are no separate accounts to manually clean up on the ArgoCD side.


12. Troubleshooting#

SymptomLikely Cause
”LOG IN VIA KEYCLOAK” button doesn’t appearargocd-cm hasn’t been applied correctly, or argocd-server hasn’t been restarted after the ConfigMap change
Login succeeds in Keycloak but ArgoCD shows “permission denied” for all resourcesThe groups claim isn’t reaching ArgoCD — recheck step 4 (the groups client scope must be Default, and the mapper must have Add to ID token: On), and make sure scopes: '[groups]' is present in argocd-rbac-cm
Group matches but the role doesn’t behave as expectedCheck the order and syntax of policy.csv — the g, <group>, role:<role> line must exactly match the group name in Keycloak (case-sensitive)
Client secret error during loginEnsure the key in the argocd-secret Secret is named exactly oidc.keycloak.clientSecret, matching what’s referenced in oidc.config
invalid_redirect_uri error from KeycloakThe redirect URI in the Keycloak client must be exactly https://argocd.example.com/auth/callback
ConfigMap changes have no effectargocd-server needs a manual restart after kubectl edit configmap — ArgoCD doesn’t always auto-reload all config sections

Summary: Create an argocd client in Keycloak with Standard Flow only → add a groups client scope with a Group Membership mapper → create groups (argocd-admins, etc.) and assign users → store the client secret in the Kubernetes argocd-secret Secret → configure oidc.config in argocd-cm → map groups to roles in argocd-rbac-cm with scopes: '[groups]' → restart argocd-server → test login → keep the local admin account as a break-glass path → offboard users by simply removing them from their Keycloak group.

Integrating Keycloak with ArgoCD — Single Sign-On via OpenID Connect
https://im-gatan.com/posts/keycloak-argocd-integration/
Author
Gatan
Published at
2026-07-19
License
CC BY-NC-SA 4.0