Skip to content

Commit 5d9a783

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(slack): preserve selector reauthorization responses
1 parent 5ad6767 commit 5d9a783

6 files changed

Lines changed: 58 additions & 4 deletions

File tree

apps/sim/app/api/tools/slack/channels/route.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,10 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
6868
})
6969
if (!resolvedCredential.ok) {
7070
return NextResponse.json(
71-
{ error: resolvedCredential.error },
71+
{
72+
error: resolvedCredential.error,
73+
...(resolvedCredential.authRequired ? { authRequired: true } : {}),
74+
},
7275
{ status: resolvedCredential.status }
7376
)
7477
}

apps/sim/app/api/tools/slack/server-resolved-selectors.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,32 @@ describe('server-resolved Slack selectors', () => {
7474
expect(providerFetch).not.toHaveBeenCalled()
7575
})
7676

77+
it.each([
78+
['channels', listChannels, '/api/tools/slack/channels'],
79+
['users', listUsers, '/api/tools/slack/users'],
80+
])(
81+
'preserves the reauthorization marker from the %s credential resolver',
82+
async (_name, handler, path) => {
83+
mocks.resolveSlackCredential.mockResolvedValue({
84+
ok: false,
85+
status: 401,
86+
error: 'Could not retrieve access token',
87+
authRequired: true,
88+
})
89+
const providerFetch = vi.fn()
90+
vi.stubGlobal('fetch', providerFetch)
91+
92+
const response = await handler(request(path, { credential: 'credential-1' }))
93+
94+
expect(response.status).toBe(401)
95+
expect(await response.json()).toEqual({
96+
error: 'Could not retrieve access token',
97+
authRequired: true,
98+
})
99+
expect(providerFetch).not.toHaveBeenCalled()
100+
}
101+
)
102+
77103
it('supports a workflowless stored credential through the route', async () => {
78104
vi.stubGlobal(
79105
'fetch',

apps/sim/app/api/tools/slack/users/route.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
5757
})
5858
if (!resolvedCredential.ok) {
5959
return NextResponse.json(
60-
{ error: resolvedCredential.error },
60+
{
61+
error: resolvedCredential.error,
62+
...(resolvedCredential.authRequired ? { authRequired: true } : {}),
63+
},
6164
{ status: resolvedCredential.status }
6265
)
6366
}

apps/sim/lib/api/contracts/selectors/slack.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const slackUsersBodySchema = credentialWorkflowBodySchema.extend({
1919
})
2020

2121
export const slackSelectorCredentialBodySchema = credentialWorkflowBodySchema
22+
export type SlackSelectorCredentialBody = z.input<typeof slackSelectorCredentialBodySchema>
2223

2324
export const slackChannelsSelectorContract = definePostSelector(
2425
'/api/tools/slack/channels',

apps/sim/lib/selectors/server/slack-credential.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,22 @@ describe('resolveSlackSelectorCredential', () => {
136136
expect(mocks.refreshToken).not.toHaveBeenCalled()
137137
})
138138

139+
it('marks a stored credential for reauthorization when token refresh returns nothing', async () => {
140+
mocks.refreshToken.mockResolvedValue(null)
141+
142+
const result = await resolveSlackSelectorCredential(principal, {
143+
credential: 'credential-1',
144+
requestId: 'request-1',
145+
})
146+
147+
expect(result).toEqual({
148+
ok: false,
149+
status: 401,
150+
error: 'Could not retrieve access token',
151+
authRequired: true,
152+
})
153+
})
154+
139155
it.each(['xoxb-literal-secret', '{{SLACK_CREDENTIAL}}'])(
140156
'requires workflow scope before resolving %s',
141157
async (credential) => {

apps/sim/lib/selectors/server/slack-credential.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export type SlackSelectorCredentialResult =
1414
isBotToken: boolean
1515
credentialAccess?: CredentialAccessResult
1616
}
17-
| { ok: false; status: number; error: string }
17+
| { ok: false; status: number; error: string; authRequired?: true }
1818

1919
async function resolveStoredSlackCredential(
2020
principal: Principal,
@@ -47,7 +47,12 @@ async function resolveStoredSlackCredential(
4747
input.requestId
4848
)
4949
if (!accessToken) {
50-
return { ok: false, status: 401, error: 'Could not retrieve access token' }
50+
return {
51+
ok: false,
52+
status: 401,
53+
error: 'Could not retrieve access token',
54+
authRequired: true,
55+
}
5156
}
5257

5358
return {

0 commit comments

Comments
 (0)