Dex is a lightweight and minimal OpenID Connect (OIDC) provider designed for simple and self-hosted authentication setups. It is easy to deploy, integrates well with reverse proxies such as Traefik, and provides centralized authentication for applications like Pangolin without the complexity and resource overhead of larger identity platforms.

This guide shows a working setup for integrating Dex as the OIDC provider for Pangolin behind Traefik.

Architecture

Example setup:

Internet
Traefik
   ├── Pangolin
   └── Dex

Example domains:

Dex:
https://dex.example.com

Pangolin:
https://pangolin.example.com

Dex Configuration

Example config.yaml:

issuer: https://dex.example.com

storage:
  type: memory

web:
  http: 0.0.0.0:5556

staticClients:
  - id: pangolin
    name: Pangolin
    secret: CHANGE_ME
    redirectURIs:
      - https://pangolin.example.com/auth/idp/5/oidc/callback

staticPasswords:
  - email: admin@example.com
    hash: "$2y$10$aQKUyEGDvtFl2SiAlKdpIevZlh90nI/0Hq0W1GuqiXIeTstk/O/8m"

Traefik dynamic_config.yml

Dex needs to be exposed directly through Traefik and should not be routed through Pangolin’s protected authentication flow. Add the following to Pangolin’s config/traefik/dynamic_config.yml:

http:
  routers:
    dex:
      entryPoints:
        - websecure
      rule: "Host(`dex.example.com`)"
      service: dex-service
      tls:
        certResolver: letsencrypt

  services:
    dex-service:
      loadBalancer:
        servers:
          - url: "http://dex:5556"

This assumes:

  • Dex container name is dex
  • Dex listens on port 5556
  • Dex and Traefik share the same Docker network

Pangolin OIDC Configuration

Configure Pangolin with the following values:

Client ID:
pangolin

Client Secret:
CHANGE_ME

Authorization URL:
https://dex.example.com/auth

Token URL:
https://dex.example.com/token

Identifier Path:
email

Email Path (Optional):
email

Name Path (Optional):
name

Scopes:
openid profile email

It is important that Identifier Path is set to email. This setup will not work using the default sub path.

Internal DNS Resolution

The Pangolin container must be able to resolve the Dex hostname internally. This helps avoid hairpin NAT or internal DNS resolution issues when Pangolin attempts to reach Dex through its public domain during the OIDC token exchange.

Add this to the Pangolin service in compose.yml:

extra_hosts:
  - "dex.example.com:192.168.100.10"

Replace 192.168.100.10 with the internal IP address of the Traefik host. You can use Tailscale IP address if you want.

Verifying Dex Discovery

Verify the OIDC discovery endpoint:

https://dex.example.com/.well-known/openid-configuration

A working configuration should return endpoints similar to:

{
  "issuer": "https://dex.example.com",
  "authorization_endpoint": "https://dex.example.com/auth",
  "token_endpoint": "https://dex.example.com/token",
  "userinfo_endpoint": "https://dex.example.com/userinfo",
  "jwks_uri": "https://dex.example.com/keys"
}

Security Notes

It is normal for Dex to be publicly accessible.

OIDC providers are expected to expose endpoints such as:

/.well-known/openid-configuration
/auth
/token
/userinfo
/keys

Security is enforced through:

  • HTTPS
  • client secrets
  • redirect URI validation
  • signed JWT tokens
  • password hashing

Final Notes

Dex provides a lightweight and simple OIDC solution for self-hosted environments and works well with Pangolin once the DNS and claim mappings are configured correctly.