Skip to content

Commit 036bfa0

Browse files
fix(credentials): align custom oauth reconnects
1 parent c9a51ae commit 036bfa0

4 files changed

Lines changed: 96 additions & 3 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import { createMockRequest } from '@sim/testing'
5+
import { beforeEach, describe, expect, it, vi } from 'vitest'
6+
7+
const mocks = vi.hoisted(() => ({
8+
checkWorkspaceAccess: vi.fn(),
9+
createConnectDraft: vi.fn(),
10+
getSession: vi.fn(),
11+
requireConfiguredOAuthClient: vi.fn(),
12+
}))
13+
14+
vi.mock('@/lib/auth', () => ({
15+
getSession: mocks.getSession,
16+
}))
17+
18+
vi.mock('@/lib/core/config/env-capabilities.server', () => ({
19+
requireConfiguredOAuthClient: mocks.requireConfiguredOAuthClient,
20+
}))
21+
22+
vi.mock('@/lib/core/utils/urls', () => ({
23+
getBaseUrl: () => 'https://sim.test',
24+
}))
25+
26+
vi.mock('@/lib/credentials/connect-draft', () => ({
27+
createConnectDraft: mocks.createConnectDraft,
28+
}))
29+
30+
vi.mock('@/lib/oauth/utils', () => ({
31+
getCanonicalScopesForProvider: () => ['instagram_business_basic'],
32+
}))
33+
34+
vi.mock('@/lib/workspaces/permissions/utils', () => ({
35+
checkWorkspaceAccess: mocks.checkWorkspaceAccess,
36+
}))
37+
38+
import { GET } from '@/app/api/auth/instagram/authorize/route'
39+
40+
describe('Instagram authorize route', () => {
41+
beforeEach(() => {
42+
vi.clearAllMocks()
43+
mocks.getSession.mockResolvedValue({
44+
user: { id: 'user-1' },
45+
session: { id: 'session-1' },
46+
})
47+
mocks.requireConfiguredOAuthClient.mockReturnValue({
48+
values: { INSTAGRAM_CLIENT_ID: 'instagram-client' },
49+
})
50+
mocks.checkWorkspaceAccess.mockResolvedValue({ canWrite: true })
51+
mocks.createConnectDraft.mockResolvedValue({ id: 'draft-created' })
52+
})
53+
54+
it('preserves an exact credential draft when workspaceId is also supplied', async () => {
55+
const request = createMockRequest(
56+
'GET',
57+
undefined,
58+
{},
59+
'https://sim.test/api/auth/instagram/authorize?workspaceId=workspace-1&draftId=draft-exact'
60+
)
61+
62+
const response = await GET(request)
63+
64+
expect(response.status).toBe(307)
65+
expect(response.headers.get('set-cookie')).toContain(
66+
'instagram_credential_draft_id=draft-exact'
67+
)
68+
expect(mocks.checkWorkspaceAccess).not.toHaveBeenCalled()
69+
expect(mocks.createConnectDraft).not.toHaveBeenCalled()
70+
})
71+
72+
it('creates a credential draft for a legacy workspace-only launch', async () => {
73+
const request = createMockRequest(
74+
'GET',
75+
undefined,
76+
{},
77+
'https://sim.test/api/auth/instagram/authorize?workspaceId=workspace-1'
78+
)
79+
80+
const response = await GET(request)
81+
82+
expect(response.status).toBe(307)
83+
expect(response.headers.get('set-cookie')).toContain(
84+
'instagram_credential_draft_id=draft-created'
85+
)
86+
expect(mocks.checkWorkspaceAccess).toHaveBeenCalledWith('workspace-1', 'user-1')
87+
expect(mocks.createConnectDraft).toHaveBeenCalledWith({
88+
userId: 'user-1',
89+
workspaceId: 'workspace-1',
90+
providerId: 'instagram',
91+
})
92+
})
93+
})

apps/sim/app/api/auth/instagram/authorize/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
3838
const { returnUrl, workspaceId, draftId } = parsed.data.query
3939
let credentialDraftId = draftId
4040

41-
if (workspaceId) {
41+
if (workspaceId && !draftId) {
4242
const access = await checkWorkspaceAccess(workspaceId, session.user.id)
4343
if (!access.canWrite) {
4444
return NextResponse.json({ error: 'Workspace write access denied' }, { status: 403 })

apps/sim/lib/credentials/application/provider-catalog.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ describe('listCredentialProviderCatalog', () => {
144144
description: 'Connect Trello.',
145145
providerFamily: 'trello',
146146
available: false,
147-
supportsReconnect: false,
147+
supportsReconnect: true,
148148
authorizationOptions: [{ providerId: 'trello', label: 'Trello' }],
149149
},
150150
{

apps/sim/lib/credentials/application/provider-catalog.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ export async function listCredentialProviderCatalog(
280280
description: service.description,
281281
providerFamily: service.baseProvider,
282282
available: visibility.isOAuthServiceVisible(service),
283-
supportsReconnect: !['trello', 'shopify'].includes(service.providerId),
283+
supportsReconnect: true,
284284
authorizationOptions,
285285
}
286286
})

0 commit comments

Comments
 (0)