Skip to content

Commit 78c0b29

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix quickbooks disconnect revocation edge case
1 parent 2e0ac29 commit 78c0b29

3 files changed

Lines changed: 23 additions & 4 deletions

File tree

apps/sim/lib/oauth/quickbooks.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,21 @@ describe('revokeQuickBooksToken', () => {
6666
await expect(result).rejects.not.toThrow('sensitive-refresh-token')
6767
})
6868

69-
it('sanitizes non-success responses', async () => {
69+
it('allows local cleanup when Intuit reports an already-invalid grant', async () => {
7070
mockFetch.mockResolvedValueOnce(
7171
new Response('sensitive-refresh-token quickbooks-client-secret', { status: 400 })
7272
)
7373

74+
await expect(revokeQuickBooksToken('sensitive-refresh-token')).resolves.toBeUndefined()
75+
})
76+
77+
it('sanitizes non-terminal non-success responses', async () => {
78+
mockFetch.mockResolvedValueOnce(
79+
new Response('sensitive-refresh-token quickbooks-client-secret', { status: 503 })
80+
)
81+
7482
const result = revokeQuickBooksToken('sensitive-refresh-token')
75-
await expect(result).rejects.toThrow('QuickBooks token revocation failed with HTTP 400')
83+
await expect(result).rejects.toThrow('QuickBooks token revocation failed with HTTP 503')
7684
await expect(result).rejects.not.toThrow('sensitive-refresh-token')
7785
await expect(result).rejects.not.toThrow('quickbooks-client-secret')
7886
})

apps/sim/lib/oauth/quickbooks.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,17 @@ export async function revokeQuickBooksToken(token: string): Promise<void> {
122122
throw new Error('QuickBooks token revocation request failed')
123123
}
124124

125+
// Intuit returns 400 when the grant is already invalid (for example, after a
126+
// user disconnects it in QuickBooks). There is no remaining remote access to
127+
// revoke in that case, so local cleanup can safely continue.
128+
if (response.status === 400) {
129+
await readResponseTextWithLimit(response, {
130+
maxBytes: QUICKBOOKS_MAX_REVOCATION_ERROR_BYTES,
131+
label: 'QuickBooks token revocation response',
132+
}).catch(() => {})
133+
return
134+
}
135+
125136
if (!response.ok) {
126137
await readResponseTextWithLimit(response, {
127138
maxBytes: QUICKBOOKS_MAX_REVOCATION_ERROR_BYTES,

scripts/check-api-validation-contracts.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ const QUERY_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/queries')
99
const SELECTOR_HOOKS_DIR = path.join(ROOT, 'apps/sim/hooks/selectors')
1010

1111
const BASELINE = {
12-
totalRoutes: 1009,
13-
zodRoutes: 1009,
12+
totalRoutes: 1010,
13+
zodRoutes: 1010,
1414
nonZodRoutes: 0,
1515
} as const
1616

0 commit comments

Comments
 (0)