Skip to content

Commit 5cf7d02

Browse files
icecrasher321Vikhyath Mondreti
andauthored
fix(oauth): fix oauth to use correct subblock value setter + remove unused local storage code (#628)
* fix(oauth): fixed oauth state not persisting in credential selector * remove unused local storage code for oauth * fix lint * selector clearance issue fix * fix typing issue * fix lint * remove cred id from logs * fix lint * works --------- Co-authored-by: Vikhyath Mondreti <vikhyathmondreti@Vikhyaths-Air.attlocal.net>
1 parent b4eda8f commit 5cf7d02

File tree

18 files changed

+405
-329
lines changed

18 files changed

+405
-329
lines changed

apps/sim/app/api/auth/oauth/token/route.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ const logger = createLogger('OAuthTokenAPI')
1414
export async function POST(request: NextRequest) {
1515
const requestId = crypto.randomUUID().slice(0, 8)
1616

17+
logger.info(`[${requestId}] OAuth token API POST request received`)
18+
1719
try {
1820
// Parse request body
1921
const body = await request.json()
@@ -38,14 +40,16 @@ export async function POST(request: NextRequest) {
3840
const credential = await getCredential(requestId, credentialId, userId)
3941

4042
if (!credential) {
43+
logger.error(`[${requestId}] Credential not found: ${credentialId}`)
4144
return NextResponse.json({ error: 'Credential not found' }, { status: 404 })
4245
}
4346

4447
try {
4548
// Refresh the token if needed
4649
const { accessToken } = await refreshTokenIfNeeded(requestId, credential, credentialId)
4750
return NextResponse.json({ accessToken }, { status: 200 })
48-
} catch (_error) {
51+
} catch (error) {
52+
logger.error(`[${requestId}] Failed to refresh access token:`, error)
4953
return NextResponse.json({ error: 'Failed to refresh access token' }, { status: 401 })
5054
}
5155
} catch (error) {

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export async function getOAuthToken(userId: string, providerId: string): Promise
8989
// Check if the token is expired and needs refreshing
9090
const now = new Date()
9191
const tokenExpiry = credential.accessTokenExpiresAt
92+
// Only refresh if we have an expiration time AND it's expired AND we have a refresh token
9293
const needsRefresh = tokenExpiry && tokenExpiry < now && !!credential.refreshToken
9394

9495
if (needsRefresh) {
@@ -166,7 +167,9 @@ export async function refreshAccessTokenIfNeeded(
166167
// Check if we need to refresh the token
167168
const expiresAt = credential.accessTokenExpiresAt
168169
const now = new Date()
169-
const needsRefresh = !expiresAt || expiresAt <= now
170+
// Only refresh if we have an expiration time AND it's expired
171+
// If no expiration time is set (newly created credentials), assume token is valid
172+
const needsRefresh = expiresAt && expiresAt <= now
170173

171174
const accessToken = credential.accessToken
172175

@@ -233,7 +236,9 @@ export async function refreshTokenIfNeeded(
233236
// Check if we need to refresh the token
234237
const expiresAt = credential.accessTokenExpiresAt
235238
const now = new Date()
236-
const needsRefresh = !expiresAt || expiresAt <= now
239+
// Only refresh if we have an expiration time AND it's expired
240+
// If no expiration time is set (newly created credentials), assume token is valid
241+
const needsRefresh = expiresAt && expiresAt <= now
237242

238243
// If token is still valid, return it directly
239244
if (!needsRefresh || !credential.refreshToken) {

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/credential-selector/components/oauth-required-modal.tsx

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {
1919
type OAuthProvider,
2020
parseProvider,
2121
} from '@/lib/oauth'
22-
import { saveToStorage } from '@/stores/workflows/persistence'
2322

2423
const logger = createLogger('OAuthRequiredModal')
2524

@@ -157,42 +156,11 @@ export function OAuthRequiredModal({
157156
(scope) => !scope.includes('userinfo.email') && !scope.includes('userinfo.profile')
158157
)
159158

160-
const handleRedirectToSettings = () => {
161-
try {
162-
// Determine the appropriate serviceId and providerId
163-
const providerId = getProviderIdFromServiceId(effectiveServiceId)
164-
165-
// Store information about the required connection
166-
saveToStorage<string>('pending_service_id', effectiveServiceId)
167-
saveToStorage<string[]>('pending_oauth_scopes', requiredScopes)
168-
saveToStorage<string>('pending_oauth_return_url', window.location.href)
169-
saveToStorage<string>('pending_oauth_provider_id', providerId)
170-
saveToStorage<boolean>('from_oauth_modal', true)
171-
172-
// Close the modal
173-
onClose()
174-
175-
// Open the settings modal with the credentials tab
176-
const event = new CustomEvent('open-settings', {
177-
detail: { tab: 'credentials' },
178-
})
179-
window.dispatchEvent(event)
180-
} catch (error) {
181-
logger.error('Error redirecting to settings:', { error })
182-
}
183-
}
184-
185159
const handleConnectDirectly = async () => {
186160
try {
187161
// Determine the appropriate serviceId and providerId
188162
const providerId = getProviderIdFromServiceId(effectiveServiceId)
189163

190-
// Store information about the required connection
191-
saveToStorage<string>('pending_service_id', effectiveServiceId)
192-
saveToStorage<string[]>('pending_oauth_scopes', requiredScopes)
193-
saveToStorage<string>('pending_oauth_return_url', window.location.href)
194-
saveToStorage<string>('pending_oauth_provider_id', providerId)
195-
196164
// Close the modal
197165
onClose()
198166

@@ -258,14 +226,6 @@ export function OAuthRequiredModal({
258226
<Button type='button' onClick={handleConnectDirectly} className='sm:order-3'>
259227
Connect Now
260228
</Button>
261-
<Button
262-
type='button'
263-
variant='secondary'
264-
onClick={handleRedirectToSettings}
265-
className='sm:order-2'
266-
>
267-
Go to Settings
268-
</Button>
269229
</DialogFooter>
270230
</DialogContent>
271231
</Dialog>

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

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,24 @@ import {
2121
type OAuthProvider,
2222
parseProvider,
2323
} from '@/lib/oauth'
24-
import { saveToStorage } from '@/stores/workflows/persistence'
24+
import type { SubBlockConfig } from '@/blocks/types'
25+
import { useSubBlockValue } from '../../hooks/use-sub-block-value'
2526
import { OAuthRequiredModal } from './components/oauth-required-modal'
2627

2728
const logger = createLogger('CredentialSelector')
2829

2930
interface CredentialSelectorProps {
30-
value: string
31-
onChange: (value: string) => void
32-
provider: OAuthProvider
33-
requiredScopes?: string[]
34-
label?: string
31+
blockId: string
32+
subBlock: SubBlockConfig
3533
disabled?: boolean
36-
serviceId?: string
3734
isPreview?: boolean
3835
previewValue?: any | null
3936
}
4037

4138
export function CredentialSelector({
42-
value,
43-
onChange,
44-
provider,
45-
requiredScopes = [],
46-
label = 'Select credential',
39+
blockId,
40+
subBlock,
4741
disabled = false,
48-
serviceId,
4942
isPreview = false,
5043
previewValue,
5144
}: CredentialSelectorProps) {
@@ -55,14 +48,22 @@ export function CredentialSelector({
5548
const [showOAuthModal, setShowOAuthModal] = useState(false)
5649
const [selectedId, setSelectedId] = useState('')
5750

51+
// Use collaborative state management via useSubBlockValue hook
52+
const [storeValue, setStoreValue] = useSubBlockValue(blockId, subBlock.id)
53+
54+
// Extract values from subBlock config
55+
const provider = subBlock.provider as OAuthProvider
56+
const requiredScopes = subBlock.requiredScopes || []
57+
const label = subBlock.placeholder || 'Select credential'
58+
const serviceId = subBlock.serviceId
59+
60+
// Get the effective value (preview or store value)
61+
const effectiveValue = isPreview && previewValue !== undefined ? previewValue : storeValue
62+
5863
// Initialize selectedId with the effective value
5964
useEffect(() => {
60-
if (isPreview && previewValue !== undefined) {
61-
setSelectedId(previewValue || '')
62-
} else {
63-
setSelectedId(value)
64-
}
65-
}, [value, isPreview, previewValue])
65+
setSelectedId(effectiveValue || '')
66+
}, [effectiveValue])
6667

6768
// Derive service and provider IDs using useMemo
6869
const effectiveServiceId = useMemo(() => {
@@ -85,7 +86,9 @@ export function CredentialSelector({
8586
// If we have a value but it's not in the credentials, reset it
8687
if (selectedId && !data.credentials.some((cred: Credential) => cred.id === selectedId)) {
8788
setSelectedId('')
88-
onChange('')
89+
if (!isPreview) {
90+
setStoreValue('')
91+
}
8992
}
9093

9194
// Auto-select logic:
@@ -99,11 +102,15 @@ export function CredentialSelector({
99102
const defaultCred = data.credentials.find((cred: Credential) => cred.isDefault)
100103
if (defaultCred) {
101104
setSelectedId(defaultCred.id)
102-
onChange(defaultCred.id)
105+
if (!isPreview) {
106+
setStoreValue(defaultCred.id)
107+
}
103108
} else if (data.credentials.length === 1) {
104109
// If only one credential, select it
105110
setSelectedId(data.credentials[0].id)
106-
onChange(data.credentials[0].id)
111+
if (!isPreview) {
112+
setStoreValue(data.credentials[0].id)
113+
}
107114
}
108115
}
109116
}
@@ -112,7 +119,7 @@ export function CredentialSelector({
112119
} finally {
113120
setIsLoading(false)
114121
}
115-
}, [effectiveProviderId, onChange, selectedId])
122+
}, [effectiveProviderId, selectedId, isPreview, setStoreValue])
116123

117124
// Fetch credentials on initial mount
118125
useEffect(() => {
@@ -121,11 +128,7 @@ export function CredentialSelector({
121128
// eslint-disable-next-line react-hooks/exhaustive-deps
122129
}, [])
123130

124-
// Update local state when external value changes
125-
useEffect(() => {
126-
const currentValue = isPreview ? previewValue : value
127-
setSelectedId(currentValue || '')
128-
}, [value, isPreview, previewValue])
131+
// This effect is no longer needed since we're using effectiveValue directly
129132

130133
// Listen for visibility changes to update credentials when user returns from settings
131134
useEffect(() => {
@@ -158,19 +161,13 @@ export function CredentialSelector({
158161
const handleSelect = (credentialId: string) => {
159162
setSelectedId(credentialId)
160163
if (!isPreview) {
161-
onChange(credentialId)
164+
setStoreValue(credentialId)
162165
}
163166
setOpen(false)
164167
}
165168

166169
// Handle adding a new credential
167170
const handleAddCredential = () => {
168-
// Store information about the required connection
169-
saveToStorage<string>('pending_service_id', effectiveServiceId)
170-
saveToStorage<string[]>('pending_oauth_scopes', requiredScopes)
171-
saveToStorage<string>('pending_oauth_return_url', window.location.href)
172-
saveToStorage<string>('pending_oauth_provider_id', effectiveProviderId)
173-
174171
// Show the OAuth modal
175172
setShowOAuthModal(true)
176173
setOpen(false)

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

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {
1919
getServiceIdFromScopes,
2020
type OAuthProvider,
2121
} from '@/lib/oauth'
22-
import { saveToStorage } from '@/stores/workflows/persistence'
2322
import { OAuthRequiredModal } from '../../credential-selector/components/oauth-required-modal'
2423

2524
export interface ConfluenceFileInfo {
@@ -355,15 +354,6 @@ export function ConfluenceFileSelector({
355354

356355
// Handle adding a new credential
357356
const handleAddCredential = () => {
358-
const effectiveServiceId = getServiceId()
359-
const providerId = getProviderId()
360-
361-
// Store information about the required connection
362-
saveToStorage<string>('pending_service_id', effectiveServiceId)
363-
saveToStorage<string[]>('pending_oauth_scopes', requiredScopes)
364-
saveToStorage<string>('pending_oauth_return_url', window.location.href)
365-
saveToStorage<string>('pending_oauth_provider_id', providerId)
366-
367357
// Show the OAuth modal
368358
setShowOAuthModal(true)
369359
setOpen(false)

0 commit comments

Comments
 (0)