Skip to content

Commit 02a993a

Browse files
perf(credentials): single-resolve in confluence spaces selector
Atlassian SAs were hitting resolveOAuthAccountId twice (once via refreshAccessTokenIfNeeded, once directly to read cloudId) and decrypting the secret twice (via getAtlassianServiceAccountToken inside refresh, then again via getAtlassianServiceAccountSecret). Resolve once up front and branch the whole flow on the result — SA path skips refresh entirely and pulls token+cloudId from a single secret read.
1 parent 287dade commit 02a993a

1 file changed

Lines changed: 31 additions & 21 deletions

File tree

  • apps/sim/app/api/tools/confluence/selector-spaces

apps/sim/app/api/tools/confluence/selector-spaces/route.ts

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,30 +44,40 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
4444
return NextResponse.json({ error: authz.error || 'Unauthorized' }, { status: 403 })
4545
}
4646

47-
const accessToken = await refreshAccessTokenIfNeeded(
48-
credential,
49-
authz.credentialOwnerUserId,
50-
requestId
51-
)
52-
if (!accessToken) {
53-
logger.error('Failed to get access token', {
54-
credentialId: credential,
55-
userId: authz.credentialOwnerUserId,
56-
})
57-
return NextResponse.json(
58-
{ error: 'Could not retrieve access token', authRequired: true },
59-
{ status: 401 }
47+
// Resolve once so we know whether this is an Atlassian SA credential before
48+
// doing any token / cloudId work. Atlassian SAs short-circuit the entire path:
49+
// the API token IS the access token, and cloudId lives in the encrypted secret —
50+
// so we skip refreshAccessTokenIfNeeded (avoids a redundant resolve+decrypt) and
51+
// skip getConfluenceCloudId (which 401s for scoped SA tokens).
52+
const resolved = await resolveOAuthAccountId(credential)
53+
const isAtlassianServiceAccount =
54+
resolved?.providerId === ATLASSIAN_SERVICE_ACCOUNT_PROVIDER_ID && !!resolved.credentialId
55+
56+
let accessToken: string | null
57+
let cloudId: string
58+
if (isAtlassianServiceAccount) {
59+
const secret = await getAtlassianServiceAccountSecret(resolved.credentialId!)
60+
accessToken = secret.apiToken
61+
cloudId = secret.cloudId
62+
} else {
63+
accessToken = await refreshAccessTokenIfNeeded(
64+
credential,
65+
authz.credentialOwnerUserId,
66+
requestId
6067
)
68+
if (!accessToken) {
69+
logger.error('Failed to get access token', {
70+
credentialId: credential,
71+
userId: authz.credentialOwnerUserId,
72+
})
73+
return NextResponse.json(
74+
{ error: 'Could not retrieve access token', authRequired: true },
75+
{ status: 401 }
76+
)
77+
}
78+
cloudId = await getConfluenceCloudId(domain, accessToken)
6179
}
6280

63-
// Atlassian service-account scoped tokens cannot call accessible-resources, so we
64-
// pull cloudId from the encrypted secret instead of discovering it at runtime.
65-
const resolved = await resolveOAuthAccountId(credential)
66-
const cloudId =
67-
resolved?.providerId === ATLASSIAN_SERVICE_ACCOUNT_PROVIDER_ID && resolved.credentialId
68-
? (await getAtlassianServiceAccountSecret(resolved.credentialId)).cloudId
69-
: await getConfluenceCloudId(domain, accessToken)
70-
7181
const cloudIdValidation = validateJiraCloudId(cloudId, 'cloudId')
7282
if (!cloudIdValidation.isValid) {
7383
return NextResponse.json({ error: cloudIdValidation.error }, { status: 400 })

0 commit comments

Comments
 (0)