mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-06-05 22:44:17 +00:00
2d1b04c637
* Multiple fixes - refresh coordinator dedup + memory pressure wire - middleware sse consolidation + timer leak + claim cache - universal cache sync backfill + isDebug gate - lazy background task race - memory monitor stw cached + refresh() api * fix(auth): suppress OIDC redirects on non-navigation requests - [x] Add isNonNavigationRequest using Sec-Fetch-Mode and Accept headers - [x] Add comprehensive TestIsNonNavigationRequest - [x] Update ServeHTTP to 401 non-navigation and AJAX requests Fixes #129 * feat(config): add custom CA and insecure skip verify for OIDC TLS - [x] Add CACertPath, CACertPEM, InsecureSkipVerify to Config - [x] Implement loadCACertPool for CA bundle loading - [x] Update HTTPClientConfig with RootCAs and InsecureSkipVerify - [x] Apply CA pool and skip verify to pooled HTTP clients - [x] Enhance configKey to distinguish TLS configs - [x] Add comprehensive ca_cert_test.go Fixes #125 * feat(oidc): add custom CA certificate support for private OIDC providers - [x] Add caCertPath, caCertPEM, insecureSkipVerify config options - [x] Update traefik.yml with new OIDC client config fields - [x] Add configuration schema descriptions for new options - [x] Update README table and add Custom CA Certificates section * Fix the documentation. * test(redis): add oversized argument rejection test - [x] Add TestRedisConn_RejectOversizedArgumentBytes - [x] Import strings package * Dependencies cleanup
96 lines
4.5 KiB
Markdown
96 lines
4.5 KiB
Markdown
# Dynamic Client Registration (RFC 7591)
|
|
|
|
The middleware can register itself with an OIDC provider at startup instead of
|
|
using a pre-provisioned `clientID` / `clientSecret`. Useful for multi-tenant
|
|
deployments, self-service integrations, and ephemeral environments.
|
|
|
|
## How it works
|
|
|
|
1. Middleware reads `registration_endpoint` from `.well-known/openid-configuration`.
|
|
2. If `clientID` is empty, it `POST`s `clientMetadata` to the registration endpoint.
|
|
3. Returned `client_id` / `client_secret` are cached, optionally persisted.
|
|
4. Subsequent requests use the registered credentials.
|
|
|
|
For multi-replica deployments, set `storageBackend: redis` so all replicas
|
|
share one client and avoid registration races.
|
|
|
|
## Configuration
|
|
|
|
```yaml
|
|
apiVersion: traefik.io/v1alpha1
|
|
kind: Middleware
|
|
metadata:
|
|
name: oidc-dcr
|
|
namespace: traefik
|
|
spec:
|
|
plugin:
|
|
traefikoidc:
|
|
providerURL: https://your-oidc-provider.com
|
|
sessionEncryptionKey: your-secure-encryption-key-min-32-chars
|
|
callbackURL: /oauth2/callback
|
|
dynamicClientRegistration:
|
|
enabled: true
|
|
persistCredentials: true
|
|
storageBackend: redis # file | redis | auto
|
|
initialAccessToken: "" # optional, for protected endpoints
|
|
registrationEndpoint: "" # optional, override discovery
|
|
credentialsFile: /tmp/oidc-client-credentials.json
|
|
redisKeyPrefix: "dcr:creds:"
|
|
clientMetadata:
|
|
redirect_uris:
|
|
- https://app.example.com/oauth2/callback
|
|
client_name: My Application
|
|
application_type: web
|
|
grant_types: [authorization_code, refresh_token]
|
|
response_types: [code]
|
|
token_endpoint_auth_method: client_secret_basic
|
|
contacts: [admin@example.com]
|
|
```
|
|
|
|
## Parameters
|
|
|
|
| Parameter | Default | Description |
|
|
|-----------|---------|-------------|
|
|
| `enabled` | `false` | Enable DCR. |
|
|
| `persistCredentials` | `false` | Save returned credentials for reuse across restarts. |
|
|
| `storageBackend` | `auto` | `file`, `redis`, or `auto` (Redis if available, else file). |
|
|
| `credentialsFile` | `/tmp/oidc-client-credentials.json` | Path for file-backed storage. Mode `0600`. |
|
|
| `redisKeyPrefix` | (none — set explicitly) | Key prefix for Redis-backed storage. The code does not inject a default; if unset, keys have no prefix. `dcr:creds:` is a sensible convention. |
|
|
| `registrationEndpoint` | discovered | Override the discovered endpoint. |
|
|
| `initialAccessToken` | none | Bearer token for protected registration endpoints. |
|
|
| `clientMetadata.redirect_uris` | required | Callback URIs for the OAuth flow. |
|
|
| `clientMetadata.client_name` | none | Human-readable client name. |
|
|
| `clientMetadata.application_type` | `web` | `web` or `native`. |
|
|
| `clientMetadata.grant_types` | `[authorization_code, refresh_token]` | OAuth grant types. |
|
|
| `clientMetadata.response_types` | `[code]` | OAuth response types. |
|
|
| `clientMetadata.token_endpoint_auth_method` | `client_secret_basic` | `client_secret_basic`, `client_secret_post`, or `none`. |
|
|
| `clientMetadata.scope` | none | Space-separated scopes. |
|
|
| `clientMetadata.contacts` | none | Admin email addresses. |
|
|
| `clientMetadata.logo_uri` | none | Logo URL for consent screens. |
|
|
| `clientMetadata.client_uri` | none | Client homepage URL. |
|
|
| `clientMetadata.policy_uri` | none | Privacy policy URL. |
|
|
| `clientMetadata.tos_uri` | none | Terms of service URL. |
|
|
|
|
## Provider support
|
|
|
|
The middleware does not gate DCR by provider — if the provider exposes a
|
|
`registration_endpoint` in its discovery document (or you set
|
|
`registrationEndpoint` explicitly), DCR will attempt registration. The table
|
|
below is informational guidance based on each provider's published support.
|
|
|
|
| Provider | DCR | Notes |
|
|
|----------|-----|-------|
|
|
| Keycloak | Yes | Enable in realm settings. |
|
|
| Auth0 | Yes | Requires Management API token. |
|
|
| Okta | Yes | Enable Dynamic Client Registration in admin console. |
|
|
| Azure AD | Limited | Use App Registration API instead. |
|
|
| Google | No | Manual registration required. |
|
|
| AWS Cognito | No | Manual registration required. |
|
|
|
|
## Security notes
|
|
|
|
- Registration endpoints must be HTTPS (loopback excepted for local dev).
|
|
- Use `initialAccessToken` in production to gate registration.
|
|
- File-backed credentials use `0600`; protect the mount path.
|
|
- The plugin marks credentials invalid when within ~5 min of `client_secret_expires_at` but does **not** automatically re-register. If your provider sets a non-zero expiry, schedule manual rotation (delete the credentials file or Redis entry, restart) before that time.
|