From ccc6f76b0eb9b1930c8c463ec9d18e6a99a5244c Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Wed, 12 Nov 2025 12:30:04 +0000 Subject: [PATCH] fixup! Add ability to set cookie prefix for session cookies ( #87 ) --- .traefik.yml | 49 ++++++++++++++++++++++++++++++++++++++++++------- README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 7 deletions(-) diff --git a/.traefik.yml b/.traefik.yml index 92ea7c9..8aa5a1d 100644 --- a/.traefik.yml +++ b/.traefik.yml @@ -109,6 +109,7 @@ testData: oidcEndSessionURL: https://accounts.google.com/logout # Provider's end session endpoint enablePKCE: false # Enables PKCE (Proof Key for Code Exchange) for additional security cookieDomain: "" # Explicit domain for session cookies (e.g., ".example.com" for multi-subdomain setups) + cookiePrefix: "" # Custom prefix for cookie names (e.g., "_oidc_myapp_" for session isolation between middleware instances) overrideScopes: false # When true, replaces default scopes instead of appending (default: false) refreshGracePeriodSeconds: 60 # Seconds before token expiry to attempt proactive refresh (default: 60) @@ -636,28 +637,62 @@ configuration: cookieDomain: type: string description: | - Explicit domain for session cookies. This is important for multi-subdomain setups + Explicit domain for session cookies. This is important for multi-subdomain setups and reverse proxy deployments to ensure consistent cookie handling. - + When set, all session cookies will use this domain. When not set, the domain is auto-detected from the request headers (X-Forwarded-Host or Host). - + Use a leading dot for subdomain-wide cookies (e.g., ".example.com" allows cookies to be shared between app.example.com, api.example.com, etc.). - + Use a specific domain for host-only cookies (e.g., "app.example.com" restricts cookies to that exact domain). - + This setting is crucial to prevent authentication issues like "CSRF token missing in session" errors that can occur when cookies are created with inconsistent domains. - + Examples: - ".example.com" - Allows all subdomains to share cookies - "app.example.com" - Restricts cookies to this specific host - + Default: "" (auto-detected from request headers) required: false + cookiePrefix: + type: string + description: | + Custom prefix for session cookie names. This is essential for running multiple + middleware instances with different authorization requirements on the same domain. + + By default, all middleware instances use the same cookie names (_oidc_raczylo_m, + _oidc_raczylo_a, etc.), which means they share session state. When you have + multiple instances with different access restrictions (e.g., one for general users + and one for admins), this session sharing can lead to authorization bypass issues. + + Setting a unique cookiePrefix for each middleware instance ensures complete + session isolation, preventing users authenticated via one middleware from + automatically gaining access to routes protected by a different middleware. + + The prefix is prepended to all session cookie names: + - Main session cookie: {prefix}m + - Access token cookie: {prefix}a + - Refresh token cookie: {prefix}r + - ID token cookie: {prefix}id + + Examples: + - "_oidc_userauth_" - For general user authentication middleware + - "_oidc_adminauth_" - For admin-only authentication middleware + - "_oidc_api_" - For API-specific authentication middleware + + Security Note: Use different cookie prefixes AND different sessionEncryptionKey + values for each middleware instance to ensure complete isolation. + + Default: "_oidc_raczylo_" (standard prefix for backward compatibility) + + See: https://github.com/lukaszraczylo/traefikoidc/issues/87 + required: false + overrideScopes: type: boolean description: | diff --git a/README.md b/README.md index 00e04dd..77d08f1 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,7 @@ The middleware supports the following configuration options: | `enablePKCE` | Enables PKCE (Proof Key for Code Exchange) for authorization code flow | `false` | `true`, `false` | | `refreshGracePeriodSeconds` | Seconds before token expiry to attempt proactive refresh | `60` | `120` | | `cookieDomain` | Explicit domain for session cookies (important for multi-subdomain setups) | auto-detected | `.example.com`, `app.example.com` | +| `cookiePrefix` | Custom prefix for session cookie names (for isolating multiple middleware instances) | `_oidc_raczylo_` | `_oidc_userauth_`, `_oidc_admin_` | | `audience` | Custom audience for access token validation (for Auth0 custom APIs, etc.) | `clientID` | `https://my-api.example.com` | | `strictAudienceValidation` | Reject sessions with access token audience mismatch (prevents token confusion attacks) | `false` | `true` | | `allowOpaqueTokens` | Enable opaque (non-JWT) access token support via RFC 7662 introspection | `false` | `true` | @@ -885,6 +886,54 @@ spec: **Important**: The `cookieDomain` parameter is crucial when running behind a reverse proxy or when your application serves multiple subdomains. Without it, cookies may be created with inconsistent domains, leading to authentication issues like "CSRF token missing in session" errors. +### With Multiple Middleware Instances (Session Isolation) + +When running multiple middleware instances with different authorization requirements (e.g., one for general users and one for admins), you must use different `cookiePrefix` values to prevent session sharing between instances: + +```yaml +# Middleware for general user authentication +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: oidc-userauth + namespace: traefik +spec: + plugin: + traefikoidc: + providerURL: https://auth.example.com + clientID: your-client-id + clientSecret: your-client-secret + sessionEncryptionKey: user-key-at-least-32-bytes-long + callbackURL: /oauth2/callback + cookiePrefix: "_oidc_userauth_" # Unique prefix for this instance +--- +# Middleware for admin authentication with stricter requirements +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: oidc-adminauth + namespace: traefik +spec: + plugin: + traefikoidc: + providerURL: https://auth.example.com + clientID: your-client-id + clientSecret: your-client-secret + sessionEncryptionKey: admin-key-at-least-32-bytes-long # Different encryption key + callbackURL: /oauth2/admin/callback # Different callback URL + cookiePrefix: "_oidc_adminauth_" # Different prefix for isolation + allowedUsers: # Restricted to specific admin users + - admin@example.com + - superadmin@example.com +``` + +**Security Note**: When running multiple instances, ensure you use: +1. **Different `cookiePrefix`** values to prevent cookie name collisions +2. **Different `sessionEncryptionKey`** values for complete session isolation +3. **Different `callbackURL`** paths to avoid routing conflicts + +This configuration prevents authorization bypass issues where a user authenticated via the general middleware could access admin-protected routes. See [issue #87](https://github.com/lukaszraczylo/traefikoidc/issues/87) for more details. + ### With Custom Logging and Rate Limiting ```yaml