In a previous post I showed you how to setup Keycloak to provide you with OpenID Connect and SAML capabilities. The problem with Keycloak is is that’s it’s a pretty big beast, whereas most of the time we don’t need all the functionality. It’s also tricky to run in a highly available fashion and is annoyingly slow to start up.

In this post we’ll drop Keycloak in favour of Dex, a small OpenID Connect Provider that supports a number of backends including LDAP. If you don’t need SAML, I’d strongly suggest you go this way instead.

Table of contents

Installing Dex

Dex is a Go binary. You can either download it straight from the project’s releases page or run it in a Docker container.

If you run it as a Docker container you’ll have to mount the configuration for Dex into the container, using something like:

docker run --name dex -p \
  -v /path/to/config.yaml:/config.yaml:ro \
  -v dex_data:/data:rw \ \
  serve /config.yaml

For this example we’ll run Dex with the built-in SQlite3 backend (used to store sessions etc.) hence the dex_data volume mount to ensure that persist. Dex can also persist using Kubernetes CRDs, etcd, MySQL, Postgres or in-memory.

Configuring Dex

A configuration for Dex looks like this:

issuer: https://<DOMAIN>
  type: sqlite3
    file: /data/database/dex.db

- type: ldap
  name: OpenLDAP
  id: ldap
    host: <LDAP_HOST>
    insecureNoSSL: false
    insecureSkipVerify: false
    bindDN: cn=dex,....
    usernamePrompt: Username
      baseDN: ou=...
      filter: "(objectClass=posixAccount)"
      username: uid
      idAttr: uid
      emailAttr: mail
      nameAttr: displayName
      baseDN: ou=...
      filter: "(objectClass=groupOfNames)"
      userAttr: DN
      groupAttr: member
      nameAttr: cn

  - id: "CLIENT_ID"
    secret: "CLIENT_SECRET"
    name: "OpenResty OIDC proxy"
      - "https://<DOMAIN>/auth"

Configuring OpenResty OIDC

The configuration is very similar to what we did for setting up the OIDC proxy in the previous post.

In auth.conf you’ll want to change scopes to:

scope = "openid email profile groups offline_access federated:id"

The federated:id will get you access to the User ID as known by the connector. In case of LDAP this will be my uid b/c that’s what’s configured for idAttr. Without it all you get is the user name, in my case displayName.

You’ll also want to change the value of $session_name to something new so we don’t try to pick up on old session cookies and the $session_secret too for good meassure.

Change the X-Auth-Userid and X-Auth-Username headers to get the value from res.id_token.federated_claims.user_id instead.


At this point everything should work exactly like before, with the main difference that you’ll be using Dex now to issue tokens and go through the login and consent flows.

Once you’ve verified everything works you can safely shutdown Keycloak.