mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-14 04:07:46 +00:00
feat: add cookiePath config to scope session cookies to subpath (#143)
Fixes #122. Co-authored-by: Hermes Agent <[email protected]> Co-authored-by: copilot-swe-agent[bot] <[email protected]>
This commit is contained in:
@@ -121,6 +121,7 @@ Full reference in [docs/CONFIGURATION.md](docs/CONFIGURATION.md).
|
||||
| `enablePKCE` | `false` | PKCE on the auth code flow. |
|
||||
| `cookieDomain` | auto | Set explicitly for multi-subdomain setups (`.example.com`). |
|
||||
| `cookiePrefix` | `_oidc_raczylo_` | Unique prefix per middleware instance to isolate sessions. |
|
||||
| `cookiePath` | `/` | Restrict cookies to a path prefix. Set to the middleware's path (e.g. `/app`) to prevent the browser from sending OIDC cookies to unprotected paths, avoiding 431 "Request Header Or Cookie Too Large" errors on mixed-use domains. |
|
||||
| `sessionMaxAge` | `86400` | Session lifetime in seconds. |
|
||||
| `refreshGracePeriodSeconds` | `60` | Proactively refresh tokens this many seconds before expiry. |
|
||||
| `maxRefreshTokenAgeSeconds` | `21600` | Heuristic max stored refresh-token lifetime (6h). Past this, the plugin treats the RT as expired without contacting the IdP — returns 401 to AJAX, full re-auth on navigations. Set `0` to disable. Tune to match your IdP's RT TTL. |
|
||||
|
||||
@@ -419,6 +419,10 @@ func NewWithContext(ctx context.Context, config *Config, next http.Handler, name
|
||||
return nil, fmt.Errorf("failed to create session manager: %w", err)
|
||||
}
|
||||
t.sessionManager = sessionManager
|
||||
if config.CookiePath != "" {
|
||||
t.sessionManager.cookiePath = config.CookiePath
|
||||
t.logger.Debugf("Using configured cookie path: %s", config.CookiePath)
|
||||
}
|
||||
t.errorRecoveryManager = NewErrorRecoveryManager(t.logger)
|
||||
|
||||
// Initialize token resilience manager with default configuration
|
||||
|
||||
+7
-1
@@ -423,6 +423,7 @@ type SessionManager struct {
|
||||
cancel context.CancelFunc
|
||||
cookieDomain string
|
||||
cookiePrefix string
|
||||
cookiePath string
|
||||
sessionMaxAge time.Duration
|
||||
activeSessions int64
|
||||
poolHits int64
|
||||
@@ -905,7 +906,12 @@ func (sm *SessionManager) EnhanceSessionSecurity(options *sessions.Options, r *h
|
||||
}
|
||||
|
||||
options.HttpOnly = true
|
||||
options.Path = "/" // Ensure cookies are available on all paths for OAuth flow
|
||||
// Use configured cookie path (default "/" for backward compatibility)
|
||||
cookiePath := sm.cookiePath
|
||||
if cookiePath == "" {
|
||||
cookiePath = "/"
|
||||
}
|
||||
options.Path = cookiePath
|
||||
|
||||
if sm.cookieDomain != "" {
|
||||
options.Domain = sm.cookieDomain
|
||||
|
||||
+24
-17
@@ -75,23 +75,30 @@ type Config struct {
|
||||
// IdPs do not expose RT TTL on the wire, so this is intentionally a
|
||||
// conservative heuristic; tune to match your provider configuration.
|
||||
// Default 21600 (6h). Set to 0 to disable the check.
|
||||
MaxRefreshTokenAgeSeconds int `json:"maxRefreshTokenAgeSeconds"`
|
||||
SessionMaxAge int `json:"sessionMaxAge"`
|
||||
RateLimit int `json:"rateLimit"`
|
||||
OverrideScopes bool `json:"overrideScopes"`
|
||||
DisableReplayDetection bool `json:"disableReplayDetection,omitempty"`
|
||||
RequireTokenIntrospection bool `json:"requireTokenIntrospection,omitempty"`
|
||||
AllowOpaqueTokens bool `json:"allowOpaqueTokens,omitempty"`
|
||||
StrictAudienceValidation bool `json:"strictAudienceValidation,omitempty"`
|
||||
EnablePKCE bool `json:"enablePKCE"`
|
||||
ForceHTTPS bool `json:"forceHTTPS"`
|
||||
AllowPrivateIPAddresses bool `json:"allowPrivateIPAddresses,omitempty"`
|
||||
MinimalHeaders bool `json:"minimalHeaders,omitempty"`
|
||||
StripAuthCookies bool `json:"stripAuthCookies,omitempty"`
|
||||
EnableBackchannelLogout bool `json:"enableBackchannelLogout,omitempty"`
|
||||
EnableFrontchannelLogout bool `json:"enableFrontchannelLogout,omitempty"`
|
||||
BackchannelLogoutURL string `json:"backchannelLogoutURL,omitempty"`
|
||||
FrontchannelLogoutURL string `json:"frontchannelLogoutURL,omitempty"`
|
||||
MaxRefreshTokenAgeSeconds int `json:"maxRefreshTokenAgeSeconds"`
|
||||
SessionMaxAge int `json:"sessionMaxAge"`
|
||||
RateLimit int `json:"rateLimit"`
|
||||
OverrideScopes bool `json:"overrideScopes"`
|
||||
DisableReplayDetection bool `json:"disableReplayDetection,omitempty"`
|
||||
RequireTokenIntrospection bool `json:"requireTokenIntrospection,omitempty"`
|
||||
AllowOpaqueTokens bool `json:"allowOpaqueTokens,omitempty"`
|
||||
StrictAudienceValidation bool `json:"strictAudienceValidation,omitempty"`
|
||||
EnablePKCE bool `json:"enablePKCE"`
|
||||
ForceHTTPS bool `json:"forceHTTPS"`
|
||||
AllowPrivateIPAddresses bool `json:"allowPrivateIPAddresses,omitempty"`
|
||||
MinimalHeaders bool `json:"minimalHeaders,omitempty"`
|
||||
StripAuthCookies bool `json:"stripAuthCookies,omitempty"`
|
||||
// CookiePath restricts session cookies to a specific path prefix instead of "/".
|
||||
// When traefikoidc protects some but not all paths on a domain, set this to the
|
||||
// middleware's path prefix (e.g. "/app-protegido") so the browser does not send
|
||||
// the OIDC session cookies to unprotected paths — preventing "Request Header
|
||||
// Or Cookie Too Large" (431) errors on those paths.
|
||||
// Default "/" (all paths, current behaviour).
|
||||
CookiePath string `json:"cookiePath,omitempty"`
|
||||
EnableBackchannelLogout bool `json:"enableBackchannelLogout,omitempty"`
|
||||
EnableFrontchannelLogout bool `json:"enableFrontchannelLogout,omitempty"`
|
||||
BackchannelLogoutURL string `json:"backchannelLogoutURL,omitempty"`
|
||||
FrontchannelLogoutURL string `json:"frontchannelLogoutURL,omitempty"`
|
||||
// CACertPath is an optional filesystem path to a PEM-encoded CA bundle used
|
||||
// to verify the OIDC provider's TLS certificate. Use this when the provider
|
||||
// is signed by an internal/private CA that is not in the system trust store.
|
||||
|
||||
Reference in New Issue
Block a user