Keycloak vs Dex for OIDC Federation in Geospatial Portals
An agency GIS portal that authenticates every analyst, contractor, and partner against its own local user table becomes a liability the moment staff turnover, inter-agency data sharing, or an audit arrives, and the fix is to federate identity so the portal trusts an external provider instead of hoarding passwords. This guide compares Keycloak and Dex as the OpenID Connect layer for GeoNode, GeoServer, and the surrounding OGC services, weighing them on the operational axes that actually decide a deployment — realm and user administration, protocol brokering, resource footprint, high availability, Kubernetes fit, token customization, group-to-role mapping, and the config-as-code discipline that keeps identity reproducible.
This guide sits within the Core Portal Architecture & Security Boundaries practice, and it assumes you have already decided where authentication belongs in the stack; here the question is narrower — which OIDC provider issues the tokens your gateway will validate, and how much identity machinery your team wants to operate to get them.
Why an agency portal federates identity in the first place
A geospatial portal is rarely the only system an agency runs. Staff already have accounts in Active Directory, a SAML-based single sign-on service, or a workforce identity provider, and the cadastral, environmental, and emergency-response datasets those staff touch carry real access-control obligations. Federating identity means the portal stops being an identity provider and becomes an OIDC relying party: it redirects the browser to a trusted issuer, receives a signed ID token and access token, and derives the user’s session and permissions from the claims inside. Passwords never reach the portal, deprovisioning happens once at the source, and every service behind the gateway validates the same token.
Both Keycloak and Dex speak OpenID Connect as defined by the OpenID Foundation, so either can sit at that federation point. The difference is philosophical and operational. Keycloak is a full standalone identity and access management server that can be your directory, broker other providers, and manage users itself. Dex is a thin OIDC provider that holds no users of its own and exists to put a standards-compliant OIDC face on an upstream identity source. That distinction drives every row of the comparison below.
An operational feature comparison
The rows above expand into a concrete operating profile. Read them as a set of trade-offs, not a scoreboard — the right choice depends entirely on whether your agency already has an authoritative directory it wants to keep.
User and realm management. Keycloak organizes everything into realms, each a fully isolated tenant with its own users, clients, roles, and login themes. The admin console lets an agency create accounts, reset credentials, enforce password policy, and require multi-factor authentication without touching an external system. Dex has no console and no user store; it authenticates against whatever connector you configure and manages nothing itself. If your portal must own its user lifecycle, that gap is decisive.
LDAP and SAML brokering. Both federate upstream. Keycloak can federate an LDAP or Active Directory tree as a user storage provider and broker external SAML or OIDC providers, optionally importing and synchronizing users into its own store. Dex brokers through connectors — LDAP, SAML 2.0, OIDC, GitHub, Microsoft — but treats the upstream as the sole source of truth and passes identity through without persisting it.
Resource footprint. Keycloak is a Java application; a production pod comfortably wants half a gigabyte or more of memory and a warm JVM before latency settles. Dex is a single static Go binary that idles in tens of megabytes. On a cost-sensitive cluster where identity is a supporting service rather than a product, that difference compounds across replicas and environments.
High availability. Keycloak achieves HA by clustering nodes against a shared relational database with an Infinispan cache for sessions; the database becomes the stateful dependency you must run well. Dex is effectively stateless when it stores its (minimal) auth-request and refresh-token state in Kubernetes custom resources or etcd, so replicas scale horizontally with no coordination beyond that backend.
Kubernetes-native fit. Dex was built for Kubernetes and reads its entire configuration from a mounted file or ConfigMap; it is the reference OIDC provider for the Kubernetes API server itself. Keycloak runs happily on Kubernetes via its operator and a StatefulSet-backed database, but it is a platform you host rather than a component you drop in. The stateful backing tier follows the same discipline described in the broader Core Portal Architecture & Security Boundaries practice.
Token and claim customization. This is where Keycloak pulls ahead for complex portals. Its protocol mappers can inject group memberships, custom attributes, audience restrictions, and computed claims into ID and access tokens, and its scriptable and client-scope machinery covers unusual requirements. Dex shapes claims mainly through its connectors — for example mapping LDAP group attributes into a groups claim — with far less room to compute or rewrite.
Group-to-role mapping. GeoNode ultimately needs to translate an incoming identity into Django groups and layer permissions. Keycloak’s group and role model, surfaced through a groups mapper, gives you a clean authoritative claim to consume. Dex forwards the upstream group attribute. Either can feed the portal, but the mapping logic and where it lives differ — the downstream half of that pipeline is covered in Mapping OIDC Group Claims to GeoNode Roles.
GitOps and config-as-code. Dex’s single YAML file is trivially version-controlled and diffable, which makes it a natural fit for a declarative pipeline. Keycloak is console-first, but realms can be exported to JSON and re-imported at startup, so config-as-code is achievable with more moving parts. Both belong under the same reproducibility discipline the platform applies elsewhere.
Maintenance burden. Keycloak ships frequent releases with occasional breaking migrations to its database schema and admin API; upgrades are a planned event. Dex changes slowly and carries almost no state to migrate. Weigh this against the capability you gain — a portal that needs Keycloak’s features will accept its upkeep.
When Keycloak fits
Choose Keycloak when the portal must be a full standalone identity provider. Reach for it when the agency wants to manage users itself — onboarding external contractors and inter-agency partners who have no account in any existing directory, enforcing its own MFA and password policy, and running self-service credential recovery. Keycloak also wins when you need protocol brokering as a first-class feature: bridging a legacy SAML provider, an LDAP directory, and modern OIDC clients through one issuer, optionally normalizing all of them into a single realm. Its rich token customization matters when downstream services demand computed claims, audience scoping, or fine-grained attribute release that a passthrough connector cannot express. Portals that consume those claims for tenant isolation should design them alongside Implementing RBAC for Multi-Tenant GIS Portals, because the claim shape and the authorization model have to agree. The canonical reference for realm, client, and mapper configuration is the Keycloak server administration documentation.
When Dex fits
Choose Dex when an authoritative identity provider already exists and you only need a compliant OIDC face in front of it. If staff live in Active Directory or a corporate SSO that speaks SAML, Dex brokers that source into clean OIDC tokens for GeoNode without duplicating a single account. It shines where footprint and simplicity are priorities — a lightweight, stateless connector that fits a modest cluster, deploys as a small binary, and defines its entire behavior in one declarative file that lives in Git next to the rest of your manifests. Dex is also the pragmatic default when the same OIDC layer must serve both the portal and the Kubernetes control plane, since it is purpose-built for that role. The configuration model and connector catalog are documented at the Dex project site. What Dex will not do is own users, run an admin console, or compute elaborate claims — if you need those, you are describing Keycloak.
Coexistence: Dex as a connector, Keycloak as the IdP
The two are not mutually exclusive, and a common pattern uses both. Keycloak acts as the agency’s standalone identity provider and user store, while Dex sits in front of a specific cluster or tool as a thin OIDC broker whose upstream connector points at Keycloak. In that arrangement Keycloak owns identity, MFA, and the user lifecycle; Dex provides a minimal, stateless OIDC endpoint tuned to one consumer — most often the Kubernetes API server — without exposing Keycloak directly. You get Keycloak’s administration and brokering at the core and Dex’s cloud-native simplicity at the edge. The token still originates from a single trusted chain, so the portal and the workload cluster validate identity against providers that agree by construction.
How the choice plugs into gateway JWT validation
Whichever provider you pick, the payoff lands at the gateway. Both Keycloak and Dex publish a standard OIDC discovery document at /.well-known/openid-configuration and expose a JSON Web Key Set (JWKS) endpoint, and that is the entire contract the gateway needs. A reverse proxy or API gateway fronting the OGC services fetches the issuer’s public keys, validates the token signature, checks the iss, aud, and exp claims, and forwards the verified identity — and any groups claim — to GeoNode and GeoServer downstream.
# nginx gateway validating an OIDC access token before proxying to OGC services
# the issuer below is provider-agnostic: point it at Keycloak or Dex
location /geoserver/ {
auth_jwt "ogc-portal";
auth_jwt_key_request /jwks_uri; # gateway fetches the issuer JWKS
# reject anything whose issuer or audience does not match the trusted provider
auth_jwt_require $jwt_claim_iss = "https://id.agency.gov/realms/geoportal"
error=401;
# forward the verified subject and group claim to the upstream OGC engine
proxy_set_header X-Auth-Subject $jwt_claim_sub;
proxy_set_header X-Auth-Groups $jwt_claim_groups;
proxy_pass http://geoserver-upstream;
}
Because the validation contract is identical across providers, the gateway configuration barely changes if you migrate from Dex to Keycloak later — you swap the discovery URL and audience, not the enforcement logic. Getting the trust boundaries and header forwarding right at this tier is the same work described in Security Boundary Mapping for OGC Services, and it is what turns a federated login into an enforced authorization decision at every OGC request. The two companion guides below take the concrete GeoNode integration one layer deeper.
Operational troubleshooting matrix
Most federation failures reduce to a mismatch between what the provider issues and what the relying party expects. Diagnose against the table before restarting anything.
| Symptom | Likely cause | Fix |
|---|---|---|
invalid_client at the token endpoint |
Client secret or redirect URI mismatch between provider and portal | Re-check the client’s secret and registered redirect URIs; regenerate the secret if rotated |
| Login loops back to the provider indefinitely | Session cookie dropped, or redirect_uri not on the allow-list |
Set SameSite/secure cookie flags; add the exact callback URL to valid redirect URIs |
Token validates but groups claim is missing |
No group mapper or connector attribute mapping configured | Add a groups protocol mapper (Keycloak) or connector group mapping (Dex); confirm the claim in a decoded token |
Gateway rejects every token as 401 |
JWKS not reachable, or iss/aud mismatch |
Verify the discovery and JWKS URLs resolve; align aud with the client ID and iss with the exact issuer |
| Keycloak nodes serve stale sessions after failover | Infinispan cache not replicating across the Keycloak node cluster | Confirm shared DB connectivity and cache stack config; verify all nodes join the same cluster |
Dex returns connector not found |
Connector ID in the auth request does not match config | Align the connector id in the Dex config with the value the client requests |
Clock-skew errors on token exp/nbf |
Provider and gateway clocks drift apart | Run NTP on all hosts; allow a small leeway window in the gateway’s validation |
Recommendation
Default to Dex when a trustworthy directory already exists and you want the lightest possible OIDC layer that a declarative pipeline can own end to end. Default to Keycloak when the portal must be the identity provider — managing agency and partner accounts, brokering multiple legacy protocols, and shaping tokens with claims that a passthrough connector cannot produce. For large multi-agency platforms the coexistence pattern is often the durable answer: Keycloak at the core for administration and brokering, Dex at the edge for a stateless, cluster-native endpoint. Whichever you choose, design the token first — its issuer, audience, and group claim are the real interface between your identity provider and every OGC service behind the gateway.
Related
- Configuring a Keycloak Realm for GeoNode SSO — the concrete realm, client, and login wiring for Keycloak.
- Mapping OIDC Group Claims to GeoNode Roles — turning a
groupsclaim into GeoNode roles on every login. - Implementing RBAC for Multi-Tenant GIS Portals — the authorization model the token claims feed.
- Security Boundary Mapping for OGC Services — where gateway JWT validation enforces the federated identity.
Up one level: Core Portal Architecture & Security Boundaries.