Skip to content

Commit 8216bad

Browse files
Combine auth and hash gate
1 parent d1872a4 commit 8216bad

1 file changed

Lines changed: 16 additions & 14 deletions

File tree

apps/sim/lib/api-key/service.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,8 @@ export async function authenticateApiKeyFromHeader(
7777
}
7878
}
7979

80-
const hashCandidate = await lookupByHash(apiKeyHeader)
81-
if (hashCandidate !== null) {
82-
return await applyHashGates(hashCandidate, options, workspaceSettings)
83-
}
80+
const hashResult = await authenticateApiKeyByHash(apiKeyHeader, options, workspaceSettings)
81+
if (hashResult !== null) return hashResult
8482

8583
// LEGACY FALLBACK — delete once `logger.warn('API key matched via fallback
8684
// decrypt loop', ...)` count stays at zero in prod. The block below is the
@@ -189,9 +187,18 @@ export async function authenticateApiKeyFromHeader(
189187
}
190188
}
191189

192-
/** Hash-only lookup — scope gates are applied separately so this can run in
193-
* parallel with `getWorkspaceBillingSettings`. */
194-
async function lookupByHash(apiKeyHeader: string): Promise<HashCandidate | null> {
190+
/**
191+
* Fast path: look up a single row by `sha256(apiKeyHeader)` and apply the
192+
* scope / expiry / permission gates. Returns `null` when no row matched the
193+
* hash (caller should fall through to the legacy scan+decrypt loop). A hash
194+
* hit that fails a gate returns a concrete `INVALID` — the key definitely
195+
* belongs to that row, it's just not authorized in this scope.
196+
*/
197+
async function authenticateApiKeyByHash(
198+
apiKeyHeader: string,
199+
options: ApiKeyAuthOptions,
200+
workspaceSettings: WorkspaceBillingSettings | null
201+
): Promise<ApiKeyAuthResult | null> {
195202
const keyHash = hashApiKey(apiKeyHeader)
196203
const rows: HashCandidate[] = await db
197204
.select({
@@ -204,14 +211,9 @@ async function lookupByHash(apiKeyHeader: string): Promise<HashCandidate | null>
204211
.from(apiKeyTable)
205212
.where(eq(apiKeyTable.keyHash, keyHash))
206213

207-
return rows.length === 0 ? null : rows[0]
208-
}
214+
if (rows.length === 0) return null
209215

210-
async function applyHashGates(
211-
record: HashCandidate,
212-
options: ApiKeyAuthOptions,
213-
workspaceSettings: WorkspaceBillingSettings | null
214-
): Promise<ApiKeyAuthResult> {
216+
const record = rows[0]
215217
const keyType = record.type as 'personal' | 'workspace'
216218

217219
if (options.userId && record.userId !== options.userId) return INVALID

0 commit comments

Comments
 (0)