[PR #9024] [CLOSED] fix(sso): scope session to authenticated org after SSO login #25280

Closed
opened 2026-04-15 22:48:26 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/9024
Author: @ping-maxwell
Created: 4/7/2026
Status: Closed

Base: mainHead: fix/sso-org-scoped-session


📝 Commits (5)

  • 740423f fix(sso): scope session to authenticated org after SSO login
  • 781c14a implement fix
  • 53bd628 chore: changeset
  • 16a392e chore: additional edge case unit tests
  • a194268 chore: improve failed session setting senarios

📊 Changes

5 files changed (+424 additions, -5 deletions)

View changed files

.changeset/pr-9024.md (+5 -0)
📝 packages/sso/src/constants.ts (+15 -0)
📝 packages/sso/src/index.ts (+69 -2)
📝 packages/sso/src/oidc.test.ts (+256 -0)
📝 packages/sso/src/routes/sso.ts (+79 -3)

📄 Description

Closes #9013

Summary

  • Fix SSO org-scoped session security issue where a user authenticated via one org's SSO could access a different org that has its own SSO configured (#9013)
  • After SSO login (OIDC or SAML), automatically set activeOrganizationId on the session to the SSO provider's org
  • Store the authenticating SSO provider ID in the verification table per session, and add a before hook on setActiveOrganization that prevents switching to an SSO-protected org the session didn't authenticate through

Migration considerations

This fix uses the verification table to track which SSO provider authenticated each session, rather than adding a ssoProviderId field to the session schema. This was a deliberate choice to avoid requiring users to run a database migration for a patch-level security fix.

The trade-off is that enforcement relies on ephemeral verification values: an extra DB lookup occurs on every setActiveOrganization call for SSO sessions, and if verification records are purged or expire unexpectedly, the restriction silently falls back to unrestricted access (fails open).

In a future minor release, we should migrate this to a proper ssoProviderId field on the session schema. That approach provides atomic writes (the SSO context is set in the same updateSession call), zero-cost lookups (the field is already loaded with the session), and guaranteed enforcement for the lifetime of the session. It will require a schema migration.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/9024 **Author:** [@ping-maxwell](https://github.com/ping-maxwell) **Created:** 4/7/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/sso-org-scoped-session` --- ### 📝 Commits (5) - [`740423f`](https://github.com/better-auth/better-auth/commit/740423f8ab1922ab5dac6318eee7610cde774ab8) fix(sso): scope session to authenticated org after SSO login - [`781c14a`](https://github.com/better-auth/better-auth/commit/781c14ab8d936e399cb7b789a373e37ad6f34b71) implement fix - [`53bd628`](https://github.com/better-auth/better-auth/commit/53bd6282edd42c62218e84e5561f661fcfbb747c) chore: changeset - [`16a392e`](https://github.com/better-auth/better-auth/commit/16a392ea8d5cb57e5493540604fe6ef75def7665) chore: additional edge case unit tests - [`a194268`](https://github.com/better-auth/better-auth/commit/a194268bf0accfa95ca0ffb1512b3f567398b14b) chore: improve failed session setting senarios ### 📊 Changes **5 files changed** (+424 additions, -5 deletions) <details> <summary>View changed files</summary> ➕ `.changeset/pr-9024.md` (+5 -0) 📝 `packages/sso/src/constants.ts` (+15 -0) 📝 `packages/sso/src/index.ts` (+69 -2) 📝 `packages/sso/src/oidc.test.ts` (+256 -0) 📝 `packages/sso/src/routes/sso.ts` (+79 -3) </details> ### 📄 Description Closes #9013 ## Summary - Fix SSO org-scoped session security issue where a user authenticated via one org's SSO could access a different org that has its own SSO configured (#9013) - After SSO login (OIDC or SAML), automatically set `activeOrganizationId` on the session to the SSO provider's org - Store the authenticating SSO provider ID in the verification table per session, and add a `before` hook on `setActiveOrganization` that prevents switching to an SSO-protected org the session didn't authenticate through ## Migration considerations This fix uses the verification table to track which SSO provider authenticated each session, rather than adding a `ssoProviderId` field to the session schema. This was a deliberate choice to avoid requiring users to run a database migration for a patch-level security fix. The trade-off is that enforcement relies on ephemeral verification values: an extra DB lookup occurs on every `setActiveOrganization` call for SSO sessions, and if verification records are purged or expire unexpectedly, the restriction silently falls back to unrestricted access (fails open). In a future minor release, we should migrate this to a proper `ssoProviderId` field on the session schema. That approach provides atomic writes (the SSO context is set in the same `updateSession` call), zero-cost lookups (the field is already loaded with the session), and guaranteed enforcement for the lifetime of the session. It will require a schema migration. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-15 22:48:26 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#25280