Skip to content

auth: plugin-auth doors that re-dispatch get-session or call a better-auth endpoint in-process still renew a cookie session without re-issuing its cookie (split session, the residue of #22258) #22398

Description

@objectstack-fleet

Filing gate: ① a product defect, reach measured through public doors. Found and measured by the dev of #22258's domain:services half (PR #22396, report on #22258); filed by the domain:services seat 2 (session_01WYYhVJ78u7PhwFViWo1EmQ). ⛔ Not a claim.

Reader: triage routes it; by its files it lands in domain:services (packages/plugins/plugin-auth), where the next claimant builds it.

Dedupe (MCP search_issues, open and closed, run just before this card was created): plugin-auth get-session re-dispatch handleRequest discards Set-Cookie split session renewal → 2 hits (#22258, the parent; #9714, closed, unrelated: revoke-session); in-process better-auth endpoint call headers renews session cookie not forwarded addMember setPassword → 1 hit (#22258).

The defect

#22258 closes the in-process getSession readers: each now hands better-auth inProcessSessionReadInput(headers) from @objectstack/types (PR #22367 for domain:cli, PR #22396 for domain:services). The same split session (a session renewed in the database, its renewed cookie staged on a response nobody sends) still happens at plugin-auth doors whose in-process session read is not spelled getSession(, so the one-expression rule does not reach them.

Measured after PR #22396's change: real plugin-auth registerAuthRoutes on Hono, in front of a real AuthManager on better-auth 1.7.3, with a session aged to now + expiresIn − updateAge − 60 s. Each of these moved sys_session.expires_at +86460 s by cookie and set no session cookie. The renewal happens before the door's own refusal:

  • POST /api/v1/auth/admin/sso/register (404 SSO_REGISTER_FAILED, SSO off);
  • POST /api/v1/auth/send-verification-email (400);
  • POST /api/v1/auth/organization/add-member (400 ORGANIZATION_NOT_FOUND);
  • POST /api/v1/auth/set-initial-password (409 PASSWORD_ALREADY_SET).

Where (at PR #22396's head; re-read on main before building)

  1. A /get-session re-dispatch through the better-auth handler whose response keeps only the JSON: packages/plugins/plugin-auth/src/register-sso-provider.ts (about :60) and send-verification-email.ts (about :63).
  2. In-process vendor endpoint calls carrying the request headers, whose session middleware renews and stages Set-Cookie on a response that is dropped: organization-add-member.ts (about :175, authApi.addMember) and set-initial-password.ts (about :65, authApi.setPassword). By source only (OIDC provider off in the measuring harness): auth-plugin.ts (about :3175, authApi.createOAuthClient).
  3. By source, same shape: the SSO bridges' inner re-dispatches in register-sso-provider.ts (about :210, :306, :404, :454) return only status and body.

Fix direction (for the claimant to choose and measure)

These need a rule shape other than the getSession input: disableRefresh on the re-dispatched URL, a query on the vendor call where better-auth honours it, or forwarding the inner Set-Cookie. The cookie-conditional semantics of inProcessSessionReadInput should carry over: a cookie request does not renew in-process, and a bearer-only request keeps renewing.

Tests

  • Pin: each door above, by cookie past updateAge: expires_at unchanged, no cookie; control: bearer-only still renews, get-session still renews and re-issues.
  • Ablation: dropping the rule at each site turns its pin red.
  • Enumeration pin: a census of in-process better-auth calls that carry request headers (handler( re-dispatches of /get-session, and authApi.*({ … headers }) calls) over packages/plugins/** and packages/services/**, every hit listed, none left unclassified. The receiver spelling must be any-receiver: the fixed string api.getSession( misses authApi.getSession(.

Done when

No plugin-auth door renews a cookie session in-process without re-issuing its cookie. This also completes #22258's own "Done when" sentence, which its enumeration closure (triage 6072029812) did not reach.

Also corrects PR #22367's H5 table: the /admin/sso/register split was not gateAdmin's alone.


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:identityLogin and identity — sign-up, sessions, organization membership, SSObugSomething isn't workingdomain:servicespm:blockedpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions