Skip to content

Commit 587d3a3

Browse files
committed
fix(api): tell a missing key owner from an owner whose ban state is null
user.banned is nullable, so a real owner with banned = NULL had every personal key refused as orphaned. Select the joined user id and test that instead; the ban and suspension checks are unchanged.
1 parent 1a605bc commit 587d3a3

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

‎apps/sim/lib/api/server/routes/v2-api-key-auth.test.ts‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,26 @@ describe('v2 API key authentication', () => {
199199
)
200200
})
201201

202+
it('accepts a personal key whose owner has never had a ban state recorded', async () => {
203+
queueTableRows(schemaMock.apiKey, [
204+
{
205+
id: 'key-1',
206+
userId: 'user-1',
207+
workspaceId: null,
208+
type: 'personal',
209+
access: 'write',
210+
expiresAt: null,
211+
ownerUserId: 'user-1',
212+
userBanned: null,
213+
userSuspendedAt: null,
214+
},
215+
])
216+
217+
const result = await authenticateV2ApiKey({ apiKey: 'secret', bearer: null })
218+
219+
expect(result.principal).toEqual(createPersonalApiKeyPrincipal())
220+
})
221+
202222
it('refuses a personal key whose owner row is gone as invalid, expired or not', async () => {
203223
for (const expiresAt of [null, new Date(Date.now() - 1)]) {
204224
queueTableRows(schemaMock.apiKey, [
@@ -209,6 +229,7 @@ describe('v2 API key authentication', () => {
209229
type: 'personal',
210230
access: 'write',
211231
expiresAt,
232+
ownerUserId: null,
212233
userBanned: null,
213234
userSuspendedAt: null,
214235
},

‎apps/sim/lib/api/server/routes/v2-api-key-auth.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,16 @@ interface ApiKeyRow {
7777
type: string
7878
access: ApiKeyAccess
7979
expiresAt: Date | null
80+
/** The joined owner's id: `null` only when the owner row is gone (`user.banned` is itself nullable). */
81+
ownerUserId: string | null
8082
userBanned: boolean | null
8183
userSuspendedAt: Date | null
8284
}
8385

8486
function requireValidRow(row: ApiKeyRow | undefined): ApiKeyRow {
8587
if (!row) throw new V2ApiKeyUnauthenticatedError()
8688
if (row.type === 'personal' && row.workspaceId === null) {
87-
if (row.userBanned === null) {
89+
if (row.ownerUserId === null) {
8890
logger.error('Personal API key is missing its credential owner', { keyId: row.id })
8991
throw new V2ApiKeyUnauthenticatedError()
9092
}
@@ -118,6 +120,7 @@ async function authenticateApiKey(apiKeyHeader: string): Promise<V2ApiKeyAuthCon
118120
type: apiKey.type,
119121
access: apiKey.access,
120122
expiresAt: apiKey.expiresAt,
123+
ownerUserId: user.id,
121124
userBanned: user.banned,
122125
userSuspendedAt: user.suspendedAt,
123126
})

0 commit comments

Comments
 (0)