Skip to content

Commit 4cceb22

Browse files
authored
fix(slack): update slack config to support refresh token rotation (#1642)
1 parent fd67fd2 commit 4cceb22

File tree

5 files changed

+72
-58
lines changed

5 files changed

+72
-58
lines changed

apps/sim/app/api/auth/oauth/utils.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,22 @@ export async function refreshTokenIfNeeded(
278278
logger.info(`[${requestId}] Successfully refreshed access token`)
279279
return { accessToken: refreshedToken, refreshed: true }
280280
} catch (error) {
281-
logger.error(`[${requestId}] Error refreshing token`, error)
281+
logger.warn(
282+
`[${requestId}] Refresh attempt failed, checking if another concurrent request succeeded`
283+
)
284+
285+
const freshCredential = await getCredential(requestId, credentialId, credential.userId)
286+
if (freshCredential?.accessToken) {
287+
const freshExpiresAt = freshCredential.accessTokenExpiresAt
288+
const stillValid = !freshExpiresAt || freshExpiresAt > new Date()
289+
290+
if (stillValid) {
291+
logger.info(`[${requestId}] Found valid token from concurrent refresh, using it`)
292+
return { accessToken: freshCredential.accessToken, refreshed: true }
293+
}
294+
}
295+
296+
logger.error(`[${requestId}] Refresh failed and no valid token found in DB`, error)
282297
throw error
283298
}
284299
}

apps/sim/app/changelog.xml/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export async function GET() {
4848
<rss version="2.0">
4949
<channel>
5050
<title>Sim Changelog</title>
51-
<link>https://sim.dev/changelog</link>
51+
<link>https://sim.ai/changelog</link>
5252
<description>Latest changes, fixes and updates in Sim.</description>
5353
<language>en-us</language>
5454
${items}

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/channel-selector/channel-selector-input.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ interface ChannelSelectorInputProps {
1919
onChannelSelect?: (channelId: string) => void
2020
isPreview?: boolean
2121
previewValue?: any | null
22+
previewContextValues?: Record<string, any>
2223
}
2324

2425
export function ChannelSelectorInput({
@@ -28,15 +29,18 @@ export function ChannelSelectorInput({
2829
onChannelSelect,
2930
isPreview = false,
3031
previewValue,
32+
previewContextValues,
3133
}: ChannelSelectorInputProps) {
3234
const params = useParams()
3335
const workflowIdFromUrl = (params?.workflowId as string) || ''
34-
// Use the proper hook to get the current value and setter (same as file-selector)
3536
const [storeValue, setStoreValue] = useSubBlockValue(blockId, subBlock.id)
36-
// Reactive upstream fields
3737
const [authMethod] = useSubBlockValue(blockId, 'authMethod')
3838
const [botToken] = useSubBlockValue(blockId, 'botToken')
3939
const [connectedCredential] = useSubBlockValue(blockId, 'credential')
40+
41+
const effectiveAuthMethod = previewContextValues?.authMethod ?? authMethod
42+
const effectiveBotToken = previewContextValues?.botToken ?? botToken
43+
const effectiveCredential = previewContextValues?.credential ?? connectedCredential
4044
const [selectedChannelId, setSelectedChannelId] = useState<string>('')
4145
const [_channelInfo, setChannelInfo] = useState<SlackChannelInfo | null>(null)
4246

@@ -49,16 +53,16 @@ export function ChannelSelectorInput({
4953
isPreview,
5054
})
5155

52-
// Choose credential strictly based on auth method
56+
// Choose credential strictly based on auth method - use effective values
5357
const credential: string =
54-
(authMethod as string) === 'bot_token'
55-
? (botToken as string) || ''
56-
: (connectedCredential as string) || ''
58+
(effectiveAuthMethod as string) === 'bot_token'
59+
? (effectiveBotToken as string) || ''
60+
: (effectiveCredential as string) || ''
5761

5862
// Determine if connected OAuth credential is foreign (not applicable for bot tokens)
5963
const { isForeignCredential } = useForeignCredential(
6064
'slack',
61-
(authMethod as string) === 'bot_token' ? '' : (connectedCredential as string) || ''
65+
(effectiveAuthMethod as string) === 'bot_token' ? '' : (effectiveCredential as string) || ''
6266
)
6367

6468
// Get the current value from the store or prop value if in preview mode (same pattern as file-selector)

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/tool-input/tool-input.tsx

Lines changed: 43 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React, { useCallback, useEffect, useState } from 'react'
2-
import { AlertCircle, PlusIcon, Server, WrenchIcon, XIcon } from 'lucide-react'
1+
import type React from 'react'
2+
import { useCallback, useEffect, useState } from 'react'
3+
import { PlusIcon, Server, WrenchIcon, XIcon } from 'lucide-react'
34
import { useParams } from 'next/navigation'
45
import { Button } from '@/components/ui/button'
56
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
@@ -374,42 +375,40 @@ function FileUploadSyncWrapper({
374375
)
375376
}
376377

377-
// Error boundary component for tool input
378-
class ToolInputErrorBoundary extends React.Component<
379-
{ children: React.ReactNode; blockName?: string },
380-
{ hasError: boolean; error?: Error }
381-
> {
382-
constructor(props: any) {
383-
super(props)
384-
this.state = { hasError: false }
385-
}
386-
387-
static getDerivedStateFromError(error: Error) {
388-
return { hasError: true, error }
389-
}
390-
391-
componentDidCatch(error: Error, info: React.ErrorInfo) {
392-
console.error('ToolInput error:', error, info)
393-
}
394-
395-
render() {
396-
if (this.state.hasError) {
397-
return (
398-
<div className='rounded-md bg-red-50 p-4 text-red-800 text-sm dark:bg-red-900/20 dark:text-red-200'>
399-
<div className='flex items-center gap-2'>
400-
<AlertCircle className='h-4 w-4' />
401-
<span className='font-medium'>Tool Configuration Error</span>
402-
</div>
403-
<p className='mt-1 text-xs opacity-80'>
404-
{this.props.blockName ? `Block "${this.props.blockName}": ` : ''}
405-
Invalid tool reference. Please check the workflow configuration.
406-
</p>
407-
</div>
408-
)
409-
}
410-
411-
return this.props.children
412-
}
378+
function ChannelSelectorSyncWrapper({
379+
blockId,
380+
paramId,
381+
value,
382+
onChange,
383+
uiComponent,
384+
disabled,
385+
previewContextValues,
386+
}: {
387+
blockId: string
388+
paramId: string
389+
value: string
390+
onChange: (value: string) => void
391+
uiComponent: any
392+
disabled: boolean
393+
previewContextValues?: Record<string, any>
394+
}) {
395+
return (
396+
<GenericSyncWrapper blockId={blockId} paramId={paramId} value={value} onChange={onChange}>
397+
<ChannelSelectorInput
398+
blockId={blockId}
399+
subBlock={{
400+
id: paramId,
401+
type: 'channel-selector' as const,
402+
title: paramId,
403+
provider: uiComponent.provider || 'slack',
404+
placeholder: uiComponent.placeholder,
405+
}}
406+
onChannelSelect={onChange}
407+
disabled={disabled}
408+
previewContextValues={previewContextValues}
409+
/>
410+
</GenericSyncWrapper>
411+
)
413412
}
414413

415414
export function ToolInput({
@@ -1060,19 +1059,14 @@ export function ToolInput({
10601059

10611060
case 'channel-selector':
10621061
return (
1063-
<ChannelSelectorInput
1062+
<ChannelSelectorSyncWrapper
10641063
blockId={blockId}
1065-
subBlock={{
1066-
id: `tool-${toolIndex || 0}-${param.id}`,
1067-
type: 'channel-selector' as const,
1068-
title: param.id,
1069-
provider: uiComponent.provider || 'slack',
1070-
placeholder: uiComponent.placeholder,
1071-
}}
1072-
onChannelSelect={onChange}
1064+
paramId={param.id}
1065+
value={value}
1066+
onChange={onChange}
1067+
uiComponent={uiComponent}
10731068
disabled={disabled}
1074-
isPreview={true}
1075-
previewValue={value}
1069+
previewContextValues={currentToolParams as any}
10761070
/>
10771071
)
10781072

apps/sim/lib/oauth/oauth.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,7 @@ function getProviderAuthConfig(provider: string): ProviderAuthConfig {
858858
clientId,
859859
clientSecret,
860860
useBasicAuth: false,
861+
supportsRefreshTokenRotation: true,
861862
}
862863
}
863864
case 'reddit': {

0 commit comments

Comments
 (0)