You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
What β A user who signs up with Google or Apple gets their workspace created, like an email signup does. Why β Today they land on the org-required page and must create a workspace by hand; most stop there. Email signup gets one automatically.
Scope
Root cause: checkOAuthUserProfile (modules/auth/controllers/auth.controller.js:307-496) creates or resolves the user, and oauthCallback (:568-602) only signs the JWT and redirects. Org provisioning (AuthOrganizationService.handleSignupOrganization) is only called by local signup (auth.signup.service.js:267) and verifyEmail (auth.controller.js:711).
The OAuth email already counts as verified (google.js:34, apple.js:36, branch 4 sets emailVerified at :428), so provisioning succeeds immediately.
Call it on every resolution (branches 1-4), not only new users: it converges on the existing ACTIVE membership, so it never creates a second org, and it self-heals accounts already orphaned by this bug with no backfill migration.
Edge cases β existing user linking a provider β converges, no second org Β· domain match β own workspace + suggestedJoin hint only Β· provider without email_verified β returns emailVerificationRequired, and the existing verification gate on organizations.required.view.vue handles it.
Tests β new modules/auth/tests/auth.oauth.signup-org.unit.tests.js (mirrors auth.verifyEmail.signup-org.unit.tests.js): called with the resolved user on all 4 branches; a provisioning failure does not break the redirect.
Correction to Why: the org-required page does have a "Create an organization" button, so this is friction, not a hard dead end. Goal = parity with email signup (workspace created automatically).
Call provisioning only when !user.currentOrganization β covers new users and users left without an org, zero extra queries/events on normal logins.
Keep only the await inside the try/catch; route any other throw in the now-async callback to oauthErrorRedirect (passport ignores the returned promise β unhandled rejection otherwise).
Refs: modules/auth/strategies/local/google.js:35, apple.js:40 (other refs still accurate).
Tests (the fix lives in oauthCallback, which sees only the resolved user): called when no currentOrganization; not called when set; not called on err/!user; a provisioning rejection still sets the cookie and 302s to /token. Await the callback promise before asserting.
Known gaps, out of scope (note in PR): suggestedJoin is not carried through OAuth; a provider-unverified email with the mailer on still gets emailVerificationRequired.
Scope: validated 2026-09-25
Created via /dev:issue
What β A user who signs up with Google or Apple gets their workspace created, like an email signup does.
Why β Today they land on the org-required page and must create a workspace by hand; most stop there. Email signup gets one automatically.
Scope
checkOAuthUserProfile(modules/auth/controllers/auth.controller.js:307-496) creates or resolves the user, andoauthCallback(:568-602) only signs the JWT and redirects. Org provisioning (AuthOrganizationService.handleSignupOrganization) is only called by local signup (auth.signup.service.js:267) andverifyEmail(auth.controller.js:711).google.js:34,apple.js:36, branch 4 setsemailVerifiedat:428), so provisioning succeeds immediately.oauthCallback's passport callback (make itasync), after the!userguard and beforejwt.sign, callawait AuthOrganizationService.handleSignupOrganization(user)in a try/catch, log-and-continue (same best-effort pattern asverifyEmail, feat(auth): wire handleSignupOrganization into verifyEmail (post-verification org setup)Β #3762/feat(auth): trigger handleSignupOrganization on verifyEmail success (best-effort)Β #3765).Edge cases β existing user linking a provider β converges, no second org Β· domain match β own workspace +
suggestedJoinhint only Β· provider withoutemail_verifiedβ returnsemailVerificationRequired, and the existing verification gate onorganizations.required.view.vuehandles it.Tests β new
modules/auth/tests/auth.oauth.signup-org.unit.tests.js(mirrorsauth.verifyEmail.signup-org.unit.tests.js): called with the resolved user on all 4 branches; a provisioning failure does not break the redirect.Refs: #3762, #3765, #3680
Update (scope re-validated)
!user.currentOrganizationβ covers new users and users left without an org, zero extra queries/events on normal logins.awaitinside the try/catch; route any other throw in the now-asynccallback tooauthErrorRedirect(passport ignores the returned promise β unhandled rejection otherwise).modules/auth/strategies/local/google.js:35,apple.js:40(other refs still accurate).oauthCallback, which sees only the resolved user): called when nocurrentOrganization; not called when set; not called onerr/!user; a provisioning rejection still sets the cookie and 302s to/token. Await the callback promise before asserting.suggestedJoinis not carried through OAuth; a provider-unverified email with the mailer on still getsemailVerificationRequired.Scope: validated 2026-09-25
Created via /dev:issue