Skip to content

Commit 3f61c4a

Browse files
waleedlatif1claude
andcommitted
fix(sso): treat caller's own user-scoped provider as owned during conflict check
Self-hosters often register SSO user-scoped via the CLI script (no SSO_ORGANIZATION_ID). If they later enable organizations and reconfigure the same domain org-scoped through the UI, the conflict check previously treated their own user-scoped row as another tenant's and returned a misleading 409. Recognize the caller's own user-scoped provider as owned so that migration is allowed, while still blocking another user's or another org's domain. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent eb5f56a commit 3f61c4a

2 files changed

Lines changed: 18 additions & 2 deletions

File tree

apps/sim/app/api/auth/sso/register/route.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,22 @@ describe('POST /api/auth/sso/register', () => {
169169
expect(mockRegisterSSOProvider).toHaveBeenCalledTimes(1)
170170
})
171171

172+
it('lets an org admin adopt their own user-scoped provider for the same domain', async () => {
173+
dbState.members = [{ organizationId: 'org1', role: 'owner' }]
174+
dbState.providers = [{ domain: 'acme.com', userId: 'u1', organizationId: null }]
175+
const res = await POST(request({ ...OIDC_BODY, orgId: 'org1' }))
176+
expect(res.status).toBe(200)
177+
expect(mockRegisterSSOProvider).toHaveBeenCalledTimes(1)
178+
})
179+
180+
it("still blocks an org admin from claiming another user's user-scoped domain", async () => {
181+
dbState.members = [{ organizationId: 'org1', role: 'owner' }]
182+
dbState.providers = [{ domain: 'acme.com', userId: 'someone-else', organizationId: null }]
183+
const res = await POST(request({ ...OIDC_BODY, orgId: 'org1' }))
184+
expect(res.status).toBe(409)
185+
expect(mockRegisterSSOProvider).not.toHaveBeenCalled()
186+
})
187+
172188
it('normalizes the domain before persisting it', async () => {
173189
dbState.members = [{ organizationId: 'org1', role: 'owner' }]
174190
const res = await POST(request({ ...OIDC_BODY, domain: 'ACME.com', orgId: 'org1' }))

apps/sim/app/api/auth/sso/register/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
7777
userId: string | null
7878
organizationId: string | null
7979
}): boolean => {
80-
if (orgId) return provider.organizationId === orgId
81-
return provider.userId === session.user.id && !provider.organizationId
80+
if (provider.userId === session.user.id && !provider.organizationId) return true
81+
return orgId ? provider.organizationId === orgId : false
8282
}
8383

8484
const existingProviders = await db

0 commit comments

Comments
 (0)