Skip to content

Commit 899978e

Browse files
committed
fix(oauth): updated oauth providers that had unstable reference IDs leading to duplicate oauth records
1 parent 5516fa3 commit 899978e

File tree

2 files changed

+55
-39
lines changed
  • apps/sim
    • app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components
    • lib/auth

2 files changed

+55
-39
lines changed

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

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client'
22

3+
import { useMemo } from 'react'
34
import { Check } from 'lucide-react'
45
import { Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader } from '@/components/emcn'
56
import { client } from '@/lib/auth/auth-client'
@@ -315,14 +316,28 @@ export function OAuthRequiredModal({
315316
}
316317
}
317318

318-
const displayScopes = requiredScopes.filter(
319-
(scope) => !scope.includes('userinfo.email') && !scope.includes('userinfo.profile')
319+
const newScopesSet = useMemo(
320+
() =>
321+
new Set(
322+
(newScopes || []).filter(
323+
(scope) => !scope.includes('userinfo.email') && !scope.includes('userinfo.profile')
324+
)
325+
),
326+
[newScopes]
320327
)
321-
const newScopesSet = new Set(
322-
(newScopes || []).filter(
328+
329+
const displayScopes = useMemo(() => {
330+
const filtered = requiredScopes.filter(
323331
(scope) => !scope.includes('userinfo.email') && !scope.includes('userinfo.profile')
324332
)
325-
)
333+
return filtered.sort((a, b) => {
334+
const aIsNew = newScopesSet.has(a)
335+
const bIsNew = newScopesSet.has(b)
336+
if (aIsNew && !bIsNew) return -1
337+
if (!aIsNew && bIsNew) return 1
338+
return 0
339+
})
340+
}, [requiredScopes, newScopesSet])
326341

327342
const handleConnectDirectly = async () => {
328343
try {

apps/sim/lib/auth/auth.ts

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ export const auth = betterAuth({
110110
account: {
111111
create: {
112112
before: async (account) => {
113+
// Check if credential already exists (same user, provider, and accountId)
114+
// This handles re-authorization: update existing credential instead of creating duplicate
113115
const existing = await db.query.account.findFirst({
114116
where: and(
115117
eq(schema.account.userId, account.userId),
@@ -119,16 +121,6 @@ export const auth = betterAuth({
119121
})
120122

121123
if (existing) {
122-
logger.warn(
123-
'[databaseHooks.account.create.before] Duplicate account detected, updating existing',
124-
{
125-
existingId: existing.id,
126-
userId: account.userId,
127-
providerId: account.providerId,
128-
accountId: account.accountId,
129-
}
130-
)
131-
132124
await db
133125
.update(schema.account)
134126
.set({
@@ -733,17 +725,17 @@ export const auth = betterAuth({
733725
scopes: ['login', 'data'],
734726
responseType: 'code',
735727
redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/wealthbox`,
736-
getUserInfo: async (tokens) => {
728+
getUserInfo: async (_tokens) => {
737729
try {
738730
logger.info('Creating Wealthbox user profile from token data')
739731

740-
const uniqueId = `wealthbox-${Date.now()}`
732+
const uniqueId = 'wealthbox-user'
741733
const now = new Date()
742734

743735
return {
744736
id: uniqueId,
745737
name: 'Wealthbox User',
746-
email: `${uniqueId.replace(/[^a-zA-Z0-9]/g, '')}@wealthbox.user`,
738+
email: `${uniqueId}@wealthbox.user`,
747739
emailVerified: false,
748740
createdAt: now,
749741
updatedAt: now,
@@ -1655,33 +1647,42 @@ export const auth = betterAuth({
16551647
redirectURI: `${getBaseUrl()}/api/auth/oauth2/callback/slack`,
16561648
getUserInfo: async (tokens) => {
16571649
try {
1658-
logger.info('Creating Slack bot profile from token data')
1650+
const response = await fetch('https://slack.com/api/auth.test', {
1651+
headers: {
1652+
Authorization: `Bearer ${tokens.accessToken}`,
1653+
},
1654+
})
16591655

1660-
// Extract user identifier from tokens if possible
1661-
let userId = 'slack-bot'
1662-
if (tokens.idToken) {
1663-
try {
1664-
const decodedToken = JSON.parse(
1665-
Buffer.from(tokens.idToken.split('.')[1], 'base64').toString()
1666-
)
1667-
if (decodedToken.sub) {
1668-
userId = decodedToken.sub
1669-
}
1670-
} catch (e) {
1671-
logger.warn('Failed to decode Slack ID token', { error: e })
1672-
}
1656+
if (!response.ok) {
1657+
logger.error('Slack auth.test failed', {
1658+
status: response.status,
1659+
statusText: response.statusText,
1660+
})
1661+
return null
16731662
}
16741663

1675-
const uniqueId = `${userId}-${Date.now()}`
1676-
const now = new Date()
1664+
const data = await response.json()
1665+
1666+
if (!data.ok) {
1667+
logger.error('Slack auth.test returned error', { error: data.error })
1668+
return null
1669+
}
1670+
1671+
const teamId = data.team_id || 'unknown'
1672+
const userId = data.user_id || data.bot_id || 'bot'
1673+
const teamName = data.team || 'Slack Workspace'
1674+
1675+
const uniqueId = `${teamId}-${userId}`
1676+
1677+
logger.info('Slack credential identifier', { teamId, userId, uniqueId, teamName })
16771678

16781679
return {
16791680
id: uniqueId,
1680-
name: 'Slack Bot',
1681-
email: `${uniqueId.replace(/[^a-zA-Z0-9]/g, '')}@slack.bot`,
1681+
name: teamName,
1682+
email: `${teamId}${userId}@slack.bot`,
16821683
emailVerified: false,
1683-
createdAt: now,
1684-
updatedAt: now,
1684+
createdAt: new Date(),
1685+
updatedAt: new Date(),
16851686
}
16861687
} catch (error) {
16871688
logger.error('Error creating Slack bot profile:', { error })
@@ -1722,7 +1723,7 @@ export const auth = betterAuth({
17221723
const data = await response.json()
17231724
const now = new Date()
17241725

1725-
const userId = data.user_id || `webflow-${Date.now()}`
1726+
const userId = data.user_id || 'user'
17261727
const uniqueId = `webflow-${userId}`
17271728

17281729
return {

0 commit comments

Comments
 (0)