# OpenID Connect for
Traefik

Production-ready OIDC authentication middleware. Drop-in replacement for oauth2-proxy and forward-auth with support for 9+ identity providers.

Get Started View on GitHub

## Features

Enterprise-grade authentication for your Traefik deployments

### Universal Provider Support

Works with Google, Azure AD, Auth0, Okta, Keycloak, Cognito, GitLab, and any OIDC-compliant provider

### Auto-Detection

Automatically detects and configures provider-specific settings from OIDC discovery

### Dynamic Registration

RFC 7591 Dynamic Client Registration with Redis storage support for multi-replica deployments

### Automatic Scope Filtering

Intelligently filters OAuth scopes based on provider capabilities from discovery documents

### Security Headers

Comprehensive security headers including CORS, CSP, HSTS, and customizable profiles

### Domain & User Restrictions

Limit access to specific email domains, individual users, or role-based groups

### Role-Based Access

Restrict access based on roles and groups from OIDC claims

### Automatic Token Refresh

Secure session handling with proactive token refresh before expiry

### Rate Limiting

Built-in protection against brute force attacks with configurable limits

### Custom Headers

Template-based headers using OIDC claims and tokens for downstream services

### PKCE Support

Proof Key for Code Exchange for enhanced security in authorization code flow

### Memory Management

Bounded caches with LRU eviction, automatic cleanup, and zero goroutine leaks

### Redis Cache

Distributed caching with Redis for multi-replica deployments with circuit breaker and health checks

### Token Introspection

RFC 7662 Token Introspection support for opaque access tokens and enhanced validation

## Supported Providers

Works with all major identity providers out of the box

#### Google

Full OIDC

#### Azure AD

Full OIDC

A0

#### Auth0

Full OIDC

OK

#### Okta

Full OIDC

KC

#### Keycloak

Full OIDC

#### AWS Cognito

Full OIDC

#### GitLab

Full OIDC

#### GitHub

OAuth 2.0

Feature | Google | Azure AD | Auth0 | Okta | Keycloak
--- | --- | --- | --- | --- | ---
ID Tokens | ✓ | ✓ | ✓ | ✓ | ✓
Refresh Tokens | ✓ | ✓ | ✓ | ✓ | ✓
Auto-Configuration | ✓ | ✓ | ✓ | ✓ | ✓
Custom Claims | Limited | ✓ | ✓ | ✓ | ✓
Group/Role Claims | Limited | ✓ | ✓ | ✓ | ✓
Self-Hosted | ✗ | ✗ | ✗ | ✗ | ✓

## Installation

Get started in under 5 minutes

### 1 Enable the Plugin

Add to your Traefik static configuration or Docker Compose command:

Add to your Traefik Helm values or static configuration:

    # docker-compose.yml - Traefik service command
    command:
      - "--experimental.plugins.traefikoidc.modulename=github.com/lukaszraczylo/traefikoidc"
      - "--experimental.plugins.traefikoidc.version=v0.7.10"

    # Or in traefik.yml static config
    experimental:
      plugins:
        traefikoidc:
          moduleName: github.com/lukaszraczylo/traefikoidc
          version: v0.7.10

    # Helm values.yaml for Traefik
    experimental:
      plugins:
        traefikoidc:
          moduleName: github.com/lukaszraczylo/traefikoidc
          version: v0.7.10

    # Or apply via additionalArguments
    additionalArguments:
      - "--experimental.plugins.traefikoidc.modulename=github.com/lukaszraczylo/traefikoidc"
      - "--experimental.plugins.traefikoidc.version=v0.7.10"

### 2 Configure the Middleware

Add middleware configuration via Docker labels:

Create a Middleware custom resource:

    # docker-compose.yml - Service labels
    labels:
      - "traefik.http.middlewares.oidc-auth.plugin.traefikoidc.providerURL=https://accounts.google.com"
      - "traefik.http.middlewares.oidc-auth.plugin.traefikoidc.clientID=your-client-id"
      - "traefik.http.middlewares.oidc-auth.plugin.traefikoidc.clientSecret=your-client-secret"
      - "traefik.http.middlewares.oidc-auth.plugin.traefikoidc.callbackURL=/oauth2/callback"
      - "traefik.http.middlewares.oidc-auth.plugin.traefikoidc.sessionEncryptionKey=your-32-byte-secret-key-here!!"

    # middleware.yaml
    apiVersion: traefik.io/v1alpha1
    kind: Middleware
    metadata:
      name: oidc-auth
      namespace: traefik
    spec:
      plugin:
        traefikoidc:
          providerURL: https://accounts.google.com
          clientID: your-client-id
          clientSecret: your-client-secret
          callbackURL: /oauth2/callback
          sessionEncryptionKey: your-32-byte-secret-key-here!!

### 3 Apply to Your Routes

Use the middleware on your services via labels:

Reference the middleware in your IngressRoute:

    # docker-compose.yml - Protected service
    services:
      my-app:
        image: my-app:latest
        labels:
          - "traefik.enable=true"
          - "traefik.http.routers.my-app.rule=Host(`app.example.com`)"
          - "traefik.http.routers.my-app.middlewares=oidc-auth"
          - "traefik.http.routers.my-app.tls=true"
          - "traefik.http.routers.my-app.tls.certresolver=letsencrypt"

    # ingressroute.yaml
    apiVersion: traefik.io/v1alpha1
    kind: IngressRoute
    metadata:
      name: my-app
      namespace: default
    spec:
      entryPoints:
        - websecure
      routes:
        - match: Host(`app.example.com`)
          kind: Rule
          middlewares:
            - name: oidc-auth
              namespace: traefik
          services:
            - name: my-app
              port: 80
      tls:
        certResolver: letsencrypt

## Configuration

Flexible options for any deployment scenario

### Required Parameters

Parameter | Description
--- | ---
`providerURL` | Base URL of your OIDC provider
`clientID` | OAuth 2.0 client identifier
`clientSecret` | OAuth 2.0 client secret. Only required when `clientAuthMethod` is unset or `client_secret_post`/`client_secret_basic`.
`sessionEncryptionKey` | 32+ byte key for session encryption
`callbackURL` | OAuth callback path (e.g., /oauth2/callback)

### Popular Optional Parameters

Parameter | Default | Description
--- | --- | ---
`forceHTTPS` | false | Required for TLS termination at load balancer (AWS ALB, etc.)
`allowedUserDomains` | none | Restrict to specific email domains
`allowedUsers` | none | Specific email addresses allowed access
`allowedRolesAndGroups` | none | Restrict to users with specific roles or groups
`roleClaimName` | "roles" | JWT claim for roles (supports namespaced claims like `https://myapp.com/roles`)
`groupClaimName` | "groups" | JWT claim for groups (supports namespaced claims)
`excludedURLs` | none | Paths that bypass authentication
`enablePKCE` | false | Enable PKCE for enhanced security
`rateLimit` | 100 | Maximum requests per second
`sessionMaxAge` | 86400 | Maximum session age in seconds (24 hours default)
`maxRefreshTokenAgeSeconds` | 21600 | Heuristic upper bound on stored refresh-token lifetime (6 hours default). Past this, the plugin treats the RT as expired without contacting the IdP. Set `0` to disable.
`cookiePrefix` | _oidc_raczylo_ | Custom prefix for session cookies
`cookieDomain` | auto-detected | Explicit domain for session cookies (multi-subdomain)
`audience` | clientID | Custom audience for access token validation
`strictAudienceValidation` | false | Reject sessions with audience mismatch
`allowOpaqueTokens` | false | Enable opaque (non-JWT) access token support
`requireTokenIntrospection` | false | Require RFC 7662 introspection for opaque tokens
`disableReplayDetection` | false | Disable JTI replay detection (for multi-replica without Redis)
`clientAuthMethod` | client_secret_post | Selects how the plugin authenticates to the token endpoint. One of `client_secret_post`, `client_secret_basic`, `private_key_jwt`.
`clientAssertionPrivateKey` | none | Inline PEM private key used to sign client assertions for `private_key_jwt`.
`clientAssertionKeyPath` | none | Path to a PEM private key file. Alternative to `clientAssertionPrivateKey`.
`clientAssertionKeyID` | none | JWS `kid` header value. Required when `clientAuthMethod` is `private_key_jwt`.
`clientAssertionAlg` | RS256 | Signing algorithm for the client assertion. One of `RS256`/`RS384`/`RS512`, `PS256`/`PS384`/`PS512`, `ES256`/`ES384`/`ES512`.

### Private Key JWT (RFC 7523)

Use this when your IdP (Entra ID, Okta, Auth0, Keycloak) pressures short-lived secrets, or when policy mandates secretless service-to-service authentication. The plugin signs a 60-second assertion with the configured private key and sends it as `client_assertion` instead of `client_secret`. Public-key registration on the IdP replaces shared-secret rotation. See RFC 7523 and issue #135.

    clientAuthMethod: private_key_jwt
    clientAssertionKeyPath: /etc/traefik/oidc-client.pem
    clientAssertionKeyID: my-client-key-2026
    # clientSecret no longer required

### Example: Google Workspace with Domain Restriction

    # docker-compose.yml labels
    labels:
      - "traefik.http.middlewares.google-oidc.plugin.traefikoidc.providerURL=https://accounts.google.com"
      - "traefik.http.middlewares.google-oidc.plugin.traefikoidc.clientID=1234567890.apps.googleusercontent.com"
      - "traefik.http.middlewares.google-oidc.plugin.traefikoidc.clientSecret=your-client-secret"
      - "traefik.http.middlewares.google-oidc.plugin.traefikoidc.callbackURL=/oauth2/callback"
      - "traefik.http.middlewares.google-oidc.plugin.traefikoidc.sessionEncryptionKey=your-32-byte-encryption-key!!"
      - "traefik.http.middlewares.google-oidc.plugin.traefikoidc.allowedUserDomains=yourcompany.com,subsidiary.com"
      - "traefik.http.middlewares.google-oidc.plugin.traefikoidc.excludedURLs=/health,/metrics,/api/public"
      - "traefik.http.middlewares.google-oidc.plugin.traefikoidc.forceHTTPS=true"
      - "traefik.http.middlewares.google-oidc.plugin.traefikoidc.logLevel=info"

    apiVersion: traefik.io/v1alpha1
    kind: Middleware
    metadata:
      name: google-oidc
      namespace: traefik
    spec:
      plugin:
        traefikoidc:
          providerURL: https://accounts.google.com
          clientID: 1234567890.apps.googleusercontent.com
          clientSecret: your-client-secret
          callbackURL: /oauth2/callback
          sessionEncryptionKey: your-32-byte-encryption-key!!
          allowedUserDomains:
            - yourcompany.com
            - subsidiary.com
          excludedURLs:
            - /health
            - /metrics
            - /api/public
          forceHTTPS: true
          logLevel: info

### Redis Cache Configuration

For multi-replica deployments, use Redis for distributed session and JTI replay detection:

Parameter | Default | Description
--- | --- | ---
`redis.enabled` | false | Enable Redis caching
`redis.address` | - | Redis server address (host:port)
`redis.password` | - | Redis password
`redis.db` | 0 | Redis database number
`redis.keyPrefix` | traefikoidc: | Key prefix for namespacing
`redis.cacheMode` | redis | Cache mode: `memory`, `redis`, or `hybrid`
`redis.poolSize` | 10 | Connection pool size
`redis.enableCircuitBreaker` | true | Enable circuit breaker for Redis failures
`redis.enableHealthCheck` | true | Enable periodic health checks
`redis.enableTLS` | false | Enable TLS for Redis connections (e.g. AWS ElastiCache in-transit encryption)
`redis.tlsSkipVerify` | false | Skip TLS server certificate verification (testing only; not recommended in production)

### Dynamic Client Registration (RFC 7591)

Automatically register your application with the OIDC provider. Supports Redis storage for multi-replica deployments:

Parameter | Default | Description
--- | --- | ---
`dynamicClientRegistration.enabled` | false | Enable dynamic client registration
`dynamicClientRegistration.persistCredentials` | true | Persist registered credentials across restarts
`dynamicClientRegistration.storageBackend` | auto | Storage backend: `file`, `redis`, or `auto` (uses Redis if available)
`dynamicClientRegistration.redisKeyPrefix` | dcr:creds: | Redis key prefix for DCR credentials
`dynamicClientRegistration.clientMetadata.redirect_uris` | - | Redirect URIs for the registered client (required)

### Example: Security Headers with CORS

    # docker-compose.yml labels
    labels:
      - "traefik.http.middlewares.oidc-secure.plugin.traefikoidc.providerURL=https://accounts.google.com"
      - "traefik.http.middlewares.oidc-secure.plugin.traefikoidc.clientID=your-client-id"
      - "traefik.http.middlewares.oidc-secure.plugin.traefikoidc.clientSecret=your-client-secret"
      - "traefik.http.middlewares.oidc-secure.plugin.traefikoidc.callbackURL=/oauth2/callback"
      - "traefik.http.middlewares.oidc-secure.plugin.traefikoidc.sessionEncryptionKey=your-32-byte-encryption-key!!"
      - "traefik.http.middlewares.oidc-secure.plugin.traefikoidc.securityHeaders.enabled=true"
      - "traefik.http.middlewares.oidc-secure.plugin.traefikoidc.securityHeaders.profile=api"
      - "traefik.http.middlewares.oidc-secure.plugin.traefikoidc.securityHeaders.corsEnabled=true"
      - "traefik.http.middlewares.oidc-secure.plugin.traefikoidc.securityHeaders.corsAllowCredentials=true"
      - "traefik.http.middlewares.oidc-secure.plugin.traefikoidc.securityHeaders.strictTransportSecurity=true"

    apiVersion: traefik.io/v1alpha1
    kind: Middleware
    metadata:
      name: oidc-secure
      namespace: traefik
    spec:
      plugin:
        traefikoidc:
          providerURL: https://accounts.google.com
          clientID: your-client-id
          clientSecret: your-client-secret
          callbackURL: /oauth2/callback
          sessionEncryptionKey: your-32-byte-encryption-key!!
          securityHeaders:
            enabled: true
            profile: api
            corsEnabled: true
            corsAllowedOrigins:
              - https://app.example.com
              - https://*.example.com
            corsAllowedMethods:
              - GET
              - POST
              - PUT
              - DELETE
            corsAllowCredentials: true
            strictTransportSecurity: true
            strictTransportSecurityMaxAge: 31536000

## Deployment Examples

Production-ready configurations for Docker Compose and Kubernetes

### Basic Setup

Complete Docker Compose setup with Traefik OIDC middleware:

Kubernetes Middleware resource using Traefik's Custom Resource Definitions:

    version: "3.8"

    services:
      traefik:
        image: traefik:v3.2
        command:
          - "--api.insecure=true"
          - "--providers.docker=true"
          - "--providers.docker.exposedbydefault=false"
          - "--entrypoints.web.address=:80"
          - "--experimental.plugins.traefikoidc.modulename=github.com/lukaszraczylo/traefikoidc"
          - "--experimental.plugins.traefikoidc.version=v0.7.10"
        ports:
          - "80:80"
          - "8080:8080"
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
        networks:
          - web

      whoami:
        image: traefik/whoami
        labels:
          - "traefik.enable=true"
          - "traefik.http.routers.whoami.rule=Host(`app.localhost`)"
          - "traefik.http.routers.whoami.entrypoints=web"
          - "traefik.http.routers.whoami.middlewares=oidc-auth"
          # OIDC Middleware Configuration
          - "traefik.http.middlewares.oidc-auth.plugin.traefikoidc.providerURL=https://accounts.google.com"
          - "traefik.http.middlewares.oidc-auth.plugin.traefikoidc.clientID=YOUR_CLIENT_ID"
          - "traefik.http.middlewares.oidc-auth.plugin.traefikoidc.clientSecret=YOUR_CLIENT_SECRET"
          - "traefik.http.middlewares.oidc-auth.plugin.traefikoidc.callbackURL=/oauth2/callback"
          - "traefik.http.middlewares.oidc-auth.plugin.traefikoidc.sessionEncryptionKey=your-32-byte-encryption-key!!"
          - "traefik.http.middlewares.oidc-auth.plugin.traefikoidc.forceHTTPS=false"
        networks:
          - web

    networks:
      web:
        external: true

    apiVersion: traefik.io/v1alpha1
    kind: Middleware
    metadata:
      name: oidc-auth
      namespace: traefik
    spec:
      plugin:
        traefikoidc:
          providerURL: https://accounts.google.com
          clientID: your-client-id
          clientSecret: your-client-secret
          sessionEncryptionKey: your-secure-encryption-key-min-32-chars
          callbackURL: /oauth2/callback
          logoutURL: /oauth2/logout
          forceHTTPS: true
          allowedUserDomains:
            - yourcompany.com
          excludedURLs:
            - /health
            - /metrics
          scopes:
            - roles
          securityHeaders:
            enabled: true
            profile: "default"
    ---
    apiVersion: traefik.io/v1alpha1
    kind: IngressRoute
    metadata:
      name: my-app
      namespace: default
    spec:
      entryPoints:
        - websecure
      routes:
        - match: Host(`app.example.com`)
          kind: Rule
          middlewares:
            - name: oidc-auth
              namespace: traefik
          services:
            - name: my-service
              port: 80
      tls:
        certResolver: letsencrypt

### With Redis Cache (Multi-Replica)

Multi-replica deployment with Redis for distributed session management:

Production-ready Kubernetes deployment with Redis for high availability:

    version: "3.8"

    services:
      redis:
        image: redis:alpine
        command: redis-server --requirepass yourpassword
        networks:
          - web

      traefik:
        image: traefik:v3.2
        deploy:
          replicas: 3
        labels:
          # OIDC Middleware with Redis
          - "traefik.http.middlewares.oidc.plugin.traefikoidc.providerURL=https://accounts.google.com"
          - "traefik.http.middlewares.oidc.plugin.traefikoidc.clientID=YOUR_CLIENT_ID"
          - "traefik.http.middlewares.oidc.plugin.traefikoidc.clientSecret=YOUR_CLIENT_SECRET"
          - "traefik.http.middlewares.oidc.plugin.traefikoidc.callbackURL=/oauth2/callback"
          - "traefik.http.middlewares.oidc.plugin.traefikoidc.sessionEncryptionKey=your-64-char-key"
          # Redis Configuration
          - "traefik.http.middlewares.oidc.plugin.traefikoidc.redis.enabled=true"
          - "traefik.http.middlewares.oidc.plugin.traefikoidc.redis.address=redis:6379"
          - "traefik.http.middlewares.oidc.plugin.traefikoidc.redis.password=yourpassword"
          - "traefik.http.middlewares.oidc.plugin.traefikoidc.redis.cacheMode=hybrid"
        networks:
          - web

    networks:
      web:
        external: true

    apiVersion: traefik.io/v1alpha1
    kind: Middleware
    metadata:
      name: oidc-with-redis
      namespace: traefik
    spec:
      plugin:
        traefikoidc:
          providerURL: https://accounts.google.com
          clientID: your-client-id
          clientSecret: your-client-secret
          sessionEncryptionKey: your-encryption-key
          callbackURL: /oauth2/callback
          forceHTTPS: true
          # Redis Configuration for multi-replica deployments
          redis:
            enabled: true
            address: "redis-service.redis-namespace:6379"
            password: "your-redis-password"
            db: 0
            keyPrefix: "traefikoidc:"
            cacheMode: "hybrid"
            enableCircuitBreaker: true
            circuitBreakerThreshold: 5
            enableHealthCheck: true
            healthCheckInterval: 30

## Security First

Built with enterprise security requirements in mind

### Token Security

- • JWT signature verification with JWK rotation
- • Replay attack detection via JTI claims
- • Strict audience and issuer validation
- • Automatic token refresh before expiry
- • Token revocation on logout

### Session Security

- • AES-256-GCM encrypted session cookies
- • CSRF protection with state parameter
- • Secure, HttpOnly, SameSite cookies
- • Configurable session timeouts
- • Bounded session cache with LRU eviction

### Security Headers

- • Content Security Policy (CSP)
- • HTTP Strict Transport Security (HSTS)
- • X-Frame-Options, X-Content-Type-Options
- • CORS configuration
- • Customizable header profiles

### Rate Limiting

- • Configurable request rate limits
- • Protection against brute force attacks
- • Per-client rate limiting
- • Graceful handling of limit exceeded
- • Customizable response codes

## IdP-Initiated Logout

Support for OIDC Back-Channel and Front-Channel Logout specifications

### Back-Channel Logout

Server-to-server logout notification. The IdP sends a signed JWT (logout_token) directly to your application when a user logs out.

- • Signed JWT logout tokens
- • Session ID (sid) based invalidation
- • Subject (sub) based invalidation
- • Works behind firewalls

### Front-Channel Logout

Browser-based logout via iframe. The IdP embeds an iframe pointing to your logout endpoint during user logout.

- • Iframe-based session termination
- • Immediate cookie invalidation
- • Simple GET request handling
- • Issuer validation

### Configuration Example

    http:
      middlewares:
        oidc-auth:
          plugin:
            traefikoidc:
              # ... other OIDC configuration ...

              # Back-Channel Logout (server-to-server)
              enableBackchannelLogout: true
              backchannelLogoutURL: "/backchannel-logout"

              # Front-Channel Logout (browser-based)
              enableFrontchannelLogout: true
              frontchannelLogoutURL: "/frontchannel-logout"

Configure your IdP with the full URLs (e.g., `https://your-app.example.com/backchannel-logout`). When a user logs out from the IdP, all their sessions across your applications will be invalidated.

## Why Choose Traefik OIDC?

A better alternative to oauth2-proxy and forward-auth

Feature | Traefik OIDC | oauth2-proxy | forward-auth
--- | --- | --- | ---
Native Plugin | ✓ | ✗ | ✗
No Extra Service | ✓ | ✗ | ✗
Auto Provider Detection | ✓ | ✗ | ✗
Dynamic Client Registration | ✓ | ✗ | ✗
Automatic Scope Filtering | ✓ | ✗ | ✗
Built-in Security Headers | ✓ | ✗ | ✗
Template Headers | ✓ | ✓ | ✓
Memory Efficient | ✓ LRU caches | Varies | Varies

## Ready to Secure Your Applications?

Get started with Traefik OIDC in minutes. Full documentation and examples available on GitHub.

View on GitHub Documentation