Skip to content

Commit cedfb93

Browse files
hotlongCopilot
andcommitted
fix(account): resume oauth2 flow after login/register on cloud IdP
When better-auth's oauth-provider redirects an unauthenticated user from /oauth2/authorize to loginPage (/_account/login), it preserves the full authorize query — client_id, redirect_uri, signed sig, state, etc. — on the target URL. After the user authenticates we must replay those same params back to /oauth2/authorize so the IdP can issue the code and 302 the user home to the RP (e.g. crm.objectos.app). Without this hand-off, the login page falls through to its default landing (window.location.assign('/')) and the user ends up on the cloud Studio dashboard while the RP never sees the callback — the SSO flow stalls silently from the user's perspective. Detect the flow via the presence of `client_id` + `redirect_uri` query params (the signed `sig` would also work but these are mandatory per the authorize spec). Apply the same fix to /register so a user who chooses to sign up mid-SSO also lands back on the RP rather than the IdP dashboard. Consent step is already bypassed for first-party platform SSO clients (seedPlatformSsoClient sets skip_consent=true), so the resumed authorize call returns the code immediately. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 6bae429 commit cedfb93

2 files changed

Lines changed: 30 additions & 0 deletions

File tree

apps/account/src/routes/login.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,24 @@ function LoginPage() {
6161
useEffect(() => {
6262
if (!user) return;
6363

64+
// OAuth-provider hand-off: when the user landed on /login because
65+
// better-auth's oauth-provider redirected them here from /oauth2/authorize
66+
// (unauthenticated user starting an SSO flow), the original authorize query
67+
// params — including `client_id`, `redirect_uri`, the signed `sig`, etc. —
68+
// are preserved on the current URL. After login succeeds we must resume
69+
// the OAuth flow by sending the same params back to /oauth2/authorize so
70+
// the IdP can issue the code and 302 the user back to the RP.
71+
//
72+
// Without this, the user ends up on the Studio dashboard (the post-login
73+
// default) and the RP never sees the callback, so the SSO flow stalls.
74+
if (typeof window !== 'undefined') {
75+
const sp = new URLSearchParams(window.location.search);
76+
if (sp.has('client_id') && sp.has('redirect_uri')) {
77+
window.location.assign(`/api/v1/auth/oauth2/authorize${window.location.search}`);
78+
return;
79+
}
80+
}
81+
6482
// If the user has organizations but no active one, auto-select the first
6583
// org before navigating away. Otherwise consumers like the Console's
6684
// `RequireOrganization` guard would bounce the user from the redirect

apps/account/src/routes/register.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ function RegisterPage() {
5454
useEffect(() => {
5555
if (!user) return;
5656

57+
// OAuth-provider hand-off: see apps/account/src/routes/login.tsx for the
58+
// full rationale. When the user landed on /register from /oauth2/authorize
59+
// we must resume the OAuth flow by replaying the signed authorize params
60+
// instead of dropping them into the Studio default landing.
61+
if (typeof window !== 'undefined') {
62+
const sp = new URLSearchParams(window.location.search);
63+
if (sp.has('client_id') && sp.has('redirect_uri')) {
64+
window.location.assign(`/api/v1/auth/oauth2/authorize${window.location.search}`);
65+
return;
66+
}
67+
}
68+
5769
// If the freshly-signed-up user already has organizations (the auth
5870
// plugin auto-provisions a personal workspace, or they accepted an
5971
// invitation), make sure one is active before navigating away. Without

0 commit comments

Comments
 (0)