Dex Cheat Sheet
Overview
Dex is an open-source OpenID Connect (OIDC) identity provider that acts as a portal to other identity sources. It serves as an identity federation hub, allowing applications to authenticate users against a variety of backends including LDAP, SAML 2.0, GitHub, GitLab, Google, Microsoft, and other OIDC providers through a single, standards-compliant OIDC interface.
Dex is commonly used with Kubernetes for cluster authentication, enabling kubectl and dashboard access through corporate identity providers. It is lightweight, written in Go, and designed for cloud-native deployments. Dex handles the complexity of integrating with multiple identity protocols while exposing a simple OIDC interface to client applications.
Installation
# Docker
docker pull ghcr.io/dexidp/dex
# Kubernetes Helm
helm repo add dex https://charts.dexidp.io
helm install dex dex/dex -f values.yaml
# Build from source
git clone https://github.com/dexidp/dex.git
cd dex
make build
./bin/dex serve config.yaml
# Verify
./bin/dex version
Core Configuration
# config.yaml
issuer: https://dex.example.com
storage:
type: sqlite3
config:
file: /var/dex/dex.db
web:
http: 0.0.0.0:5556
telemetry:
http: 0.0.0.0:5558
oauth2:
skipApprovalScreen: true
responseTypes: ["code", "token", "id_token"]
staticClients:
- id: my-app
name: "My Application"
redirectURIs:
- "http://localhost:3000/callback"
secret: ZXhhbXBsZS1hcHAtc2VjcmV0
- id: kubernetes
name: "Kubernetes"
redirectURIs:
- "http://localhost:8000"
secret: a3ViZXJuZXRlcy1zZWNyZXQ=
connectors:
- type: github
id: github
name: GitHub
config:
clientID: $GITHUB_CLIENT_ID
clientSecret: $GITHUB_CLIENT_SECRET
redirectURI: https://dex.example.com/callback
orgs:
- name: my-org
teams:
- developers
- devops
enablePasswordDB: true
staticPasswords:
- email: "admin@example.com"
hash: "$2a$10$..."
username: "admin"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
Connector Types
LDAP Connector
connectors:
- type: ldap
id: ldap
name: LDAP
config:
host: ldap.example.com:636
insecureNoSSL: false
insecureSkipVerify: false
rootCA: /etc/dex/ldap-ca.crt
bindDN: cn=admin,dc=example,dc=com
bindPW: admin-password
userSearch:
baseDN: ou=users,dc=example,dc=com
filter: "(objectClass=inetOrgPerson)"
username: uid
idAttr: uid
emailAttr: mail
nameAttr: displayName
groupSearch:
baseDN: ou=groups,dc=example,dc=com
filter: "(objectClass=groupOfNames)"
userMatchers:
- userAttr: DN
groupAttr: member
nameAttr: cn
SAML 2.0 Connector
connectors:
- type: saml
id: corporate-sso
name: "Corporate SSO"
config:
ssoURL: https://idp.example.com/saml/sso
ca: /etc/dex/saml-ca.crt
redirectURI: https://dex.example.com/callback
usernameAttr: name
emailAttr: email
groupsAttr: groups
entityIssuer: https://dex.example.com/callback
ssoIssuer: https://idp.example.com
nameIDPolicyFormat: emailAddress
Google Connector
connectors:
- type: google
id: google
name: Google
config:
clientID: $GOOGLE_CLIENT_ID
clientSecret: $GOOGLE_CLIENT_SECRET
redirectURI: https://dex.example.com/callback
hostedDomains:
- example.com
groups:
- engineering@example.com
- product@example.com
serviceAccountFilePath: /etc/dex/google-sa.json
adminEmail: admin@example.com
GitLab Connector
connectors:
- type: gitlab
id: gitlab
name: GitLab
config:
clientID: $GITLAB_CLIENT_ID
clientSecret: $GITLAB_CLIENT_SECRET
redirectURI: https://dex.example.com/callback
baseURL: https://gitlab.example.com
groups:
- my-group
- my-group/subgroup
useLoginAsID: false
OIDC Connector (Generic)
connectors:
- type: oidc
id: other-provider
name: "Other OIDC Provider"
config:
issuer: https://accounts.provider.com
clientID: $OIDC_CLIENT_ID
clientSecret: $OIDC_CLIENT_SECRET
redirectURI: https://dex.example.com/callback
scopes:
- openid
- profile
- email
- groups
getUserInfo: true
insecureSkipEmailVerified: false
claimMapping:
groups: roles
Kubernetes Integration
# kube-apiserver flags
# --oidc-issuer-url=https://dex.example.com
# --oidc-client-id=kubernetes
# --oidc-username-claim=email
# --oidc-groups-claim=groups
# --oidc-ca-file=/etc/kubernetes/pki/dex-ca.crt
# RBAC for OIDC groups
# ClusterRoleBinding for devops group
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: oidc-devops-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: Group
name: "devops"
apiGroup: rbac.authorization.k8s.io
# Configure kubectl with OIDC
kubectl config set-credentials oidc-user \
--auth-provider=oidc \
--auth-provider-arg=idp-issuer-url=https://dex.example.com \
--auth-provider-arg=client-id=kubernetes \
--auth-provider-arg=client-secret=a3ViZXJuZXRlcy1zZWNyZXQ= \
--auth-provider-arg=refresh-token=REFRESH_TOKEN \
--auth-provider-arg=id-token=ID_TOKEN
Storage Backends
# SQLite (development)
storage:
type: sqlite3
config:
file: /var/dex/dex.db
# PostgreSQL (production)
storage:
type: postgres
config:
host: postgres.example.com
port: 5432
database: dex
user: dex
password: $DEX_DB_PASSWORD
ssl:
mode: verify-ca
caFile: /etc/dex/db-ca.crt
# MySQL
storage:
type: mysql
config:
host: mysql.example.com
port: 3306
database: dex
user: dex
password: $DEX_DB_PASSWORD
# Kubernetes CRDs
storage:
type: kubernetes
config:
inCluster: true
Advanced Usage
Custom Claims and Scopes
oauth2:
responseTypes: ["code", "token", "id_token"]
skipApprovalScreen: true
# Custom scopes
passwordConnector: local
Expiration Settings
expiry:
deviceRequests: 5m
signingKeys: 6h
idTokens: 24h
refreshTokens:
reuseInterval: 3s
validIfNotUsedFor: 2160h # 90 days
absoluteLifetime: 3960h # 165 days
High Availability
# Kubernetes Helm values for HA
replicaCount: 3
storage:
type: postgres
config:
host: postgres-primary.example.com
ingress:
enabled: true
hosts:
- host: dex.example.com
paths:
- path: /
pathType: Prefix
Configuration
# Environment variables
export DEX_DB_PASSWORD="database-password"
export GITHUB_CLIENT_ID="github-oauth-client-id"
export GITHUB_CLIENT_SECRET="github-oauth-client-secret"
export GOOGLE_CLIENT_ID="google-oauth-client-id"
export GOOGLE_CLIENT_SECRET="google-oauth-client-secret"
# Start Dex
dex serve config.yaml
# Docker run
docker run -d \
--name dex \
-p 5556:5556 \
-v $(pwd)/config.yaml:/etc/dex/config.yaml \
-v $(pwd)/dex.db:/var/dex/dex.db \
ghcr.io/dexidp/dex serve /etc/dex/config.yaml
Troubleshooting
| Issue | Solution |
|---|---|
| Discovery endpoint 404 | Verify issuer URL matches exactly what Dex serves |
| LDAP bind failed | Check bindDN and bindPW; test with ldapsearch directly |
| SAML redirect loop | Verify entityIssuer and redirectURI in SAML connector config |
| No groups in token | Ensure group search is configured; check groupsAttr mapping |
| Kubernetes auth fails | Verify --oidc-issuer-url matches Dex issuer exactly |
| Token expired | Adjust expiry.idTokens and refreshTokens settings |
| Connector not showing | Check connector config syntax; look at Dex logs for errors |
| Database migration error | Run dex serve which auto-migrates; check DB permissions |