Skip to content

Commit 7eded6c

Browse files
committed
fix(oauth): persist rotated Microsoft refresh tokens
Microsoft Entra rotates refresh tokens on every refresh and expects clients to replace the stored token with the new one. The Microsoft provider config was missing supportsRefreshTokenRotation, so the rotated refresh_token returned by Azure AD was silently discarded and the original token from initial OAuth connect was reused indefinitely — causing periodic 'Failed to refresh access token' errors for Excel, Teams, Outlook, OneDrive, SharePoint, Planner, AD, and Dataverse integrations.
1 parent badfeae commit 7eded6c

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,36 @@ describe('OAuth Token Refresh', () => {
389389
})
390390
})
391391

392+
it.concurrent(
393+
'should rotate refresh token for Microsoft providers (microsoft, outlook, onedrive, sharepoint)',
394+
async () => {
395+
const microsoftProviders = ['microsoft', 'outlook', 'onedrive', 'sharepoint']
396+
const oldRefreshToken = 'old_microsoft_refresh_token'
397+
const rotatedRefreshToken = 'rotated_microsoft_refresh_token'
398+
399+
for (const providerId of microsoftProviders) {
400+
const mockFetch = vi.fn().mockResolvedValue({
401+
ok: true,
402+
json: async () => ({
403+
access_token: 'new_access_token',
404+
expires_in: 3600,
405+
refresh_token: rotatedRefreshToken,
406+
}),
407+
})
408+
409+
const result = await withMockFetch(mockFetch, () =>
410+
refreshOAuthToken(providerId, oldRefreshToken)
411+
)
412+
413+
expect(result).toEqual({
414+
accessToken: 'new_access_token',
415+
expiresIn: 3600,
416+
refreshToken: rotatedRefreshToken,
417+
})
418+
}
419+
}
420+
)
421+
392422
it.concurrent('should use original refresh token when new one is not provided', async () => {
393423
const refreshToken = 'original_refresh_token'
394424

apps/sim/lib/oauth/oauth.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,7 @@ function getProviderAuthConfig(provider: string): ProviderAuthConfig {
11631163
clientId,
11641164
clientSecret,
11651165
useBasicAuth: false,
1166+
supportsRefreshTokenRotation: true,
11661167
}
11671168
}
11681169
case 'linear': {

0 commit comments

Comments
 (0)