Skip to content

SSO Phase 4c: Block non-SSO logins#1936

Merged
GregorShear merged 20 commits intomainfrom
greg/login-intercept
Apr 3, 2026
Merged

SSO Phase 4c: Block non-SSO logins#1936
GregorShear merged 20 commits intomainfrom
greg/login-intercept

Conversation

@GregorShear
Copy link
Copy Markdown
Contributor

@GregorShear GregorShear commented Mar 23, 2026

Summary

  • Intercept sso_required:<domain> errors from Supabase auth to redirect users to their organization's SSO provider
  • Wraps all supabase fetch requests (specifically auth requests - both login and token refresh) and looks for sso-required errors
  • Adds a full-page interstitial (FullPageSSONotSatisfied) that explains SSO is required and provides a one-click redirect to the tenant's identity provider via signInWithSSO({ domain })

Test plan

  • Trigger sso_required error on OAuth login → interstitial appears, SSO redirect works
  • Trigger sso_required error on token refresh → interstitial appears
  • Normal login flows (no SSO requirement) are unaffected

@GregorShear GregorShear changed the base branch from main to greg/invites_sso_redirect March 23, 2026 22:21
@GregorShear GregorShear force-pushed the greg/login-intercept branch 2 times, most recently from a45bea7 to c1680b6 Compare March 26, 2026 02:40
@GregorShear GregorShear force-pushed the greg/invites_sso_redirect branch 3 times, most recently from c331ea6 to 441e224 Compare March 26, 2026 03:34
@GregorShear GregorShear force-pushed the greg/login-intercept branch 2 times, most recently from 9a4e45c to bdafc04 Compare March 26, 2026 03:42
@GregorShear GregorShear force-pushed the greg/invites_sso_redirect branch 3 times, most recently from 6d98c48 to 6b39967 Compare March 26, 2026 04:53
@GregorShear GregorShear force-pushed the greg/login-intercept branch from bdafc04 to 5af80fe Compare March 26, 2026 15:38
@GregorShear GregorShear force-pushed the greg/invites_sso_redirect branch from 6b39967 to 6779097 Compare March 28, 2026 02:16
Base automatically changed from greg/invites_sso_redirect to greg/invites2 March 30, 2026 16:32
Base automatically changed from greg/invites2 to main March 31, 2026 15:11
@GregorShear GregorShear force-pushed the greg/login-intercept branch 6 times, most recently from 64b0b36 to 13bf542 Compare April 2, 2026 01:26
Comment thread src/components/fullPage/SSONotSatisfied.tsx Outdated
@GregorShear GregorShear requested a review from travjenkins April 2, 2026 02:35
@GregorShear GregorShear marked this pull request as ready for review April 2, 2026 02:36
@GregorShear GregorShear requested a review from a team as a code owner April 2, 2026 02:37
Comment thread src/components/fullPage/SSONotSatisfied.tsx Outdated
Comment thread src/components/fullPage/SSONotSatisfied.tsx Outdated
Comment thread src/pages/SSORequired.tsx
Comment thread src/context/GlobalProviders.tsx
Comment thread src/context/GlobalProviders.tsx
Comment thread src/pages/SSORequired.tsx
Copy link
Copy Markdown
Member

@travjenkins travjenkins left a comment

Choose a reason for hiding this comment

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

A few more tweaks

Comment thread src/pages/SSORequired.tsx
};

return (
<FullPageDialog>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Really struggled to hide the avatar in the upper right - my understanding is that setUserDetails(null) should do it, but I think the authStateChange listener defined in User/index.tsx was restoring that value.

So anyway, I'm punting on that and using this FullPageDialog wrapper component that omits the top bar entirely. Let me know what you think.

@travjenkins

Image

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.

Yup - this is fine and what I expected the faster solution to be :D

Comment thread src/context/GlobalProviders.tsx Outdated
Comment on lines +70 to +75
// Remove the session directly from localStorage.
// We can't use supabaseClient.auth.signOut() here
// because the token refresh that triggered this
// interceptor holds Supabase's internal session
// lock, so calling signOut deadlocks and hangs.
localStorage.removeItem(supabaseStorageKey);
Copy link
Copy Markdown
Contributor Author

@GregorShear GregorShear Apr 2, 2026

Choose a reason for hiding this comment

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

some more weirdness - need to remove the session from local storage to prevent retrying the token refresh request. Normally we'd do that with supabaseClient.auth.signOut(), but calling that in this function hangs, i think because supabase already has a lock on the session during the refresh cycle (which we are interrupting here).

another option would be to call signOut() in a useEffect in the SsoRequired component. I kinda like having the logic centralized here, though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

talked to travis - moving this to the SsoRequired useEffect and calling the actual signout() function

@GregorShear GregorShear added the change:planned This is a planned change label Apr 2, 2026
@GregorShear GregorShear force-pushed the greg/login-intercept branch from 0e293c0 to 9f268b1 Compare April 3, 2026 13:35
Comment thread src/pages/SSORequired.tsx
Copy link
Copy Markdown
Member

@travjenkins travjenkins left a comment

Choose a reason for hiding this comment

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

lgtm - we'll wanna keep an eye on 401 GQL calls but doubt that'll be an issue in prod

@GregorShear GregorShear merged commit fb75ea2 into main Apr 3, 2026
7 checks passed
@GregorShear GregorShear deleted the greg/login-intercept branch April 3, 2026 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:planned This is a planned change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants