Skip to content

fix(openid-connect): scope session cookie per route to avoid state collision#13671

Closed
shreemaan-abhishek wants to merge 2 commits into
apache:masterfrom
shreemaan-abhishek:fix/openid-connect-per-route-session-cookie
Closed

fix(openid-connect): scope session cookie per route to avoid state collision#13671
shreemaan-abhishek wants to merge 2 commits into
apache:masterfrom
shreemaan-abhishek:fix/openid-connect-per-route-session-cookie

Conversation

@shreemaan-abhishek

@shreemaan-abhishek shreemaan-abhishek commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Description

When two openid-connect routes on the same host share a session.secret, they both fall back to lua-resty-session's default cookie name "session". An unauthenticated visit to route A stores the pre-login state/nonce in that cookie; a subsequent unauthenticated visit to route B (carrying the same cookie) overwrites it. When route A's callback then arrives, the state no longer matches and lua-resty-openidc returns:

state from argument: <A> does not match state restored from session: <B>

surfacing as an HTTP 500 to the user. This is purely a cookie-naming collision, not an auth bypass.

This PR defaults an unset session.cookie_name to a stable per-route name derived from the route id (falling back to client_id), so sibling routes each get their own session cookie and no longer clobber each other's pre-login state.

Behavior change / opt-in sharing: cross-route session sharing (e.g. SSO across routes on the same host with redis storage) previously worked implicitly via the shared default cookie name. With per-route defaults, sharing is now explicit: set the same session.cookie_name on each route that should share a session. An operator-set session.cookie_name is always honored. The redis session-sharing test is updated to set a shared cookie_name accordingly.

On upgrade, in-flight sessions using the old default "session" cookie are not recognized and users re-authenticate once. Config API and behavior contracts are otherwise unchanged.

Which issue(s) this PR fixes:

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible (config and behavior contracts preserved; see the sharing/re-login notes above)

…llision

Two openid-connect routes on the same host that share a session.secret
both used resty.session's default cookie name "session", so an
unauthenticated visit to one route overwrote the pre-login state (state,
nonce) stored for the other. Completing the first route's callback then
failed with "state ... does not match state restored from session"
(HTTP 500).

Default an unset session.cookie_name to a per-route name derived from the
route id (falling back to client_id), so sibling routes no longer share
one cookie. An explicit session.cookie_name is still respected.
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 8, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses OpenID Connect Authorization Code flow failures caused by session cookie name collisions when multiple openid-connect routes on the same host share the same session.secret. It introduces a derived, stable per-route default session.cookie_name (while still honoring operator-configured session.cookie_name) and adds test coverage plus documentation updates.

Changes:

  • Derive a per-route default session cookie name and apply it when session.cookie_name is unset.
  • Add unit-style tests for cookie name derivation / session option building, plus an end-to-end-style isolation test.
  • Document the new defaulting behavior and the reason for explicitly setting session.cookie_name when sharing sessions is desired.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
apisix/plugins/openid-connect.lua Derives a per-route session cookie name and applies it during openidc.authenticate() session initialization.
t/plugin/openid-connect10.t Adds tests validating cookie name derivation and session.cookie_name defaulting/override behavior.
t/plugin/openid-connect11.t Adds an integration-style test ensuring sibling routes produce distinct session cookies when sharing session.secret.
docs/en/latest/plugins/openid-connect.md Documents the new derived default for session.cookie_name and how to explicitly share a session cookie across routes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +41 to +45
local seed = ctx and ctx.route_id or conf.client_id
if not seed then
return nil
end
return "session_" .. string.sub(ngx.md5(seed), 1, 16)
Comment on lines +66 to +68
if default_cookie_name and not session_conf.cookie_name then
session_conf.cookie_name = default_cookie_name
end
Cross-route session sharing now requires a shared session.cookie_name
since the default cookie name is per-route. Set an explicit shared
cookie_name on both routes in the redis session-sharing test so it keeps
exercising the shared-session refresh flow.

@membphis membphis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nic-6443 nic-6443 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If users want to distinguish login status across multiple routes, they can manually configure different Cookie names. Configuring the same Cookie name among multiple routes is also a reasonable scenario in itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants