From d21233b8692a7a5fb4301386ad0536ff078ad8f9 Mon Sep 17 00:00:00 2001 From: Tanner Linsley Date: Thu, 29 Oct 2026 17:52:08 -0600 Subject: [PATCH] fix: preserve OAuth grants when refreshing legacy-scope tokens --- harness-tests/core/shared-oauth-db.test.ts | 21 +++++++++++++++++++++ src/auth/oauthClient.server.ts | 1 + 2 files changed, 22 insertions(+) diff --git a/harness-tests/core/shared-oauth-db.test.ts b/harness-tests/core/shared-oauth-db.test.ts index 803fa476c..8fd00e4da 100644 --- a/harness-tests/core/shared-oauth-db.test.ts +++ b/harness-tests/core/shared-oauth-db.test.ts @@ -264,6 +264,27 @@ describe.skipIf(!fixture.url)('OAuth grants in PostgreSQL', () => { }) }) + it('revokes access tokens created by legacy-scope refresh', async () => { + const code = await createAuthorizationCode({ + userId, + clientId, + redirectUri, + codeChallenge: challenge, + }) + const issued = await exchangeAuthorizationCode({ + code, + codeVerifier: verifier, + redirectUri, + }) + if (!issued.success) throw new Error(issued.error) + const refreshed = await refreshAccessToken(issued.refreshToken) + if (!refreshed.success) throw new Error(refreshed.error) + await revokeOAuthGrant(issued.refreshToken, clientId) + expect((await validateOAuthToken(refreshed.accessToken)).success).toBe( + false, + ) + }) + it('requires service authentication for introspection and isolates identity grants', async () => { const issued = await issue() const request = (authorization: string) => diff --git a/src/auth/oauthClient.server.ts b/src/auth/oauthClient.server.ts index 8018d0191..78c04196f 100644 --- a/src/auth/oauthClient.server.ts +++ b/src/auth/oauthClient.server.ts @@ -512,6 +512,7 @@ export async function refreshAccessToken( userId: token.userId, clientId: token.clientId, scope: 'api', + grantId: token.grantId, expiresAt: accessExpiresAt, }) .returning({ id: oauthAccessTokens.id })