fix(studio): keep organization_slug in oauth signup redirect (#48352)

Email signups inside a partner OAuth flow lose `organization_slug` on
the post-confirmation redirect: the OAuth branch in `SignUpForm`
hand-builds the `/authorize` return URL from only `auth_id` and `token`,
and the component's nuqs hook never reads the param at all. The consent
screen uses `organization_slug` to preselect and lock the partner's
requested org, so affected multi-org users land on an empty picker and
the partner's requested org is silently dropped. The GitHub-OAuth signup
path goes through `buildPathWithParams` and preserves the param, which
is how this went unnoticed.

I validated the drop in production traffic before fixing: joining
sign-up pageviews to their post-signup `/authorize` return on the
`auth_id` URL param (30d), 28 of 36 resolvable flows came back without
the slug, and the 8 that kept it were the GitHub branch.

## To test

Needs a partner OAuth authorize link that includes an org, opened
signed-out: `/dashboard/authorize?auth_id=<id>&organization_slug=<slug>`
(note `auth_id` records expire quickly, so generate a fresh authorize
request from an OAuth app).

- [x] Sign up with email from that flow; after confirmation the redirect
lands on `/authorize` with `organization_slug` still in the URL
- [ ] Consent screen shows the requested org preselected and locked
- [x] Same flow without `organization_slug` behaves as before (no
trailing empty params in the redirect URL)

## Linear

- fixes GROWTH-1031




<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved sign-up redirects during authentication flows by preserving
invitation tokens and organization information.
  * Enhanced handling of sign-up links containing organization details.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Pamela Chia authored and GitHub committed 2026-07-27 23:02:05 +08:00
1 parent a72259b3f0
commit 01541b95cb
1 file changed
+7 -1
@@ -67,6 +67,7 @@ export const SignUpForm = () => {
const [searchParams] = useQueryStates({
auth_id: parseAsString.withDefault(''),
token: parseAsString.withDefault(''),
organization_slug: parseAsString.withDefault(''),
})
const trackFunnelError = useTrackFunnelError()
@@ -102,7 +103,12 @@ export const SignUpForm = () => {
let redirectTo: string
if (isInsideOAuthFlow) {
redirectTo = `${redirectUrlBase}/authorize?auth_id=${searchParams.auth_id}${searchParams.token && `&token=${searchParams.token}`}`
const authorizeParams = new URLSearchParams({ auth_id: searchParams.auth_id })
if (searchParams.token) authorizeParams.set('token', searchParams.token)
if (searchParams.organization_slug) {
authorizeParams.set('organization_slug', searchParams.organization_slug)
}
redirectTo = `${redirectUrlBase}/authorize?${authorizeParams.toString()}`
} else {
// Use getRedirectToPath to handle redirect_to parameter and other query params
const { returnTo } = router.query