From 49536035a2ae26adb2d663ba2fa1d80257cb3ca8 Mon Sep 17 00:00:00 2001 From: Michi Gysel Date: Wed, 14 Jan 2026 23:18:27 +0100 Subject: [PATCH] fix: session refresh handling in OIDC provider (#3267) * Fix session refresh handling in OIDC provider - `s.Refreshed` was always `false` as the session object was not updated - `ValidateURL` is, by default, not configured for OIDC providers. Access token validation now only happens when a validation endpoint is available. Signed-off-by: Michael Gysel * Update changelog Signed-off-by: Michael Gysel --------- Signed-off-by: Michael Gysel --- CHANGELOG.md | 1 + providers/oidc.go | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70cfaa3e..1467837f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - [#3292](https://github.com/oauth2-proxy/oauth2-proxy/pull/3292) chore(deps): upgrade gomod and bump to golang v1.25.5 (@tuunit) - [#3304](https://github.com/oauth2-proxy/oauth2-proxy/pull/3304) fix: added conditional so default is not always set and env vars are honored fixes 3303 (@pixeldrew) - [#3264](https://github.com/oauth2-proxy/oauth2-proxy/pull/3264) fix: more aggressively truncate logged access_token (@MartinNowak / @tuunit) +- [#3267](https://github.com/oauth2-proxy/oauth2-proxy/pull/3267) fix: Session refresh handling in OIDC provider (@gysel) # V7.13.0 diff --git a/providers/oidc.go b/providers/oidc.go index b0be63bc..aa022f63 100644 --- a/providers/oidc.go +++ b/providers/oidc.go @@ -117,14 +117,12 @@ func (p *OIDCProvider) ValidateSession(ctx context.Context, s *sessions.SessionS // https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokenResponse // The ID Token is optional in the Refresh Token Response - // TODO: @tuunit remove dependency on refreshed flag and only rely on presence of access_token - // in accordance with the spec. For now, keep existing behavior. if s.Refreshed { - if !validateToken(ctx, p, s.AccessToken, makeOIDCHeader(s.AccessToken)) { + validateEndpointAvailable := p.Data().ValidateURL != nil && p.Data().ValidateURL.String() != "" + if validateEndpointAvailable && !validateToken(ctx, p, s.AccessToken, makeOIDCHeader(s.AccessToken)) { logger.Errorf("access_token validation failed") return false } - return true } @@ -190,9 +188,8 @@ func (p *OIDCProvider) redeemRefreshToken(ctx context.Context, s *sessions.Sessi return fmt.Errorf("unable create new session state from response: %v", err) } - // It's possible that if the refresh token isn't in the token response the - // session will not contain an id token. - // If it doesn't it's probably better to retain the old one + // It's possible that a refresh does not renew the ID Token. + // If it doesn't, it's probably better to retain the old one. if newSession.IDToken != "" { s.IDToken = newSession.IDToken s.Email = newSession.Email @@ -205,6 +202,7 @@ func (p *OIDCProvider) redeemRefreshToken(ctx context.Context, s *sessions.Sessi s.RefreshToken = newSession.RefreshToken s.CreatedAt = newSession.CreatedAt s.ExpiresOn = newSession.ExpiresOn + s.Refreshed = newSession.Refreshed return nil }