Skip to content

Commit cac0534

Browse files
committed
fix(auth): colocate OAuth grant revocation with access tokens
1 parent 33e5dc4 commit cac0534

3 files changed

Lines changed: 13 additions & 17 deletions

File tree

‎apps/sim/lib/auth/auth.ts‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ import {
5454
recordAuthenticationSecurityAudit,
5555
recordPasswordResetAudit,
5656
} from '@/lib/auth/lifecycle-audit'
57-
import { hashOAuthToken } from '@/lib/auth/oauth-access-token'
58-
import { revokeUserOAuthGrants } from '@/lib/auth/oauth-grants'
57+
import { hashOAuthToken, revokeUserOAuthGrants } from '@/lib/auth/oauth-access-token'
5958
import {
6059
consentRequestNamesClient,
6160
OAUTH_ACCESS_TOKEN_PREFIX,

‎apps/sim/lib/auth/oauth-access-token.ts‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { AsyncLocalStorage } from 'node:async_hooks'
22
import type { OAuthAccessTokenPrincipal } from '@sim/auth/principal'
33
import { db } from '@sim/db'
4-
import { oauthAccessToken, oauthClient, user } from '@sim/db/schema'
4+
import { oauthAccessToken, oauthClient, oauthTokenFamily, user } from '@sim/db/schema'
55
import { createLogger, setRequestAuth } from '@sim/logger'
66
import { sha256Hex } from '@sim/security/hash'
77
import { eq, sql } from 'drizzle-orm'
@@ -11,6 +11,7 @@ import {
1111
OAUTH_API_READ_SCOPE,
1212
oauthScopeSatisfies,
1313
} from '@/lib/auth/oauth-provider'
14+
import type { DbOrTx } from '@/lib/db/types'
1415

1516
const logger = createLogger('OAuthAccessToken')
1617

@@ -174,3 +175,13 @@ export async function verifyOAuthAccessToken(
174175
expiresAt: row.expiresAt,
175176
}
176177
}
178+
179+
/**
180+
* Revokes every refresh family and access token a user holds. Families outlive the session that
181+
* minted them (`session_id` is set null on delete), so deleting sessions alone leaves them
182+
* rotatable. Consents are kept, so a legitimate client re-authorizes without a new consent prompt.
183+
*/
184+
export async function revokeUserOAuthGrants(userId: string, database: DbOrTx = db): Promise<void> {
185+
await database.delete(oauthTokenFamily).where(eq(oauthTokenFamily.userId, userId))
186+
await database.delete(oauthAccessToken).where(eq(oauthAccessToken.userId, userId))
187+
}

‎apps/sim/lib/auth/oauth-grants.ts‎

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)