Repository navigation
feat(auth): record throttled lastUsedAt on authentication and expose in key listing - #587
Conversation
|
@gospeltout Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
|
Merged as Merged locally. The branch predated the Three things on top. 1. There was no migration, so the column would never have reached a live databaseThis PR is the first schema change since #577 landed this morning, and that changes the rules in a way nothing in the repo would have told you. Startup used to run: which diffed the live database against And the failure would have been silent: every Added: -- prisma/migrations/20261023120000_api_key_last_used_at/migration.sql
ALTER TABLE "api_keys" ADD COLUMN "last_used_at" TIMESTAMP(3);Nullable with no default on purpose — Worth reading 2. Regenerating the baseline instead would have broken a fresh database — and #577's test demanded exactly thatWorth writing down, because I walked into it myself. My first attempt regenerated So the baseline stays behind // it('has an init/baseline migration that reproduces schema.prisma exactly')
expect(actual).toBe(expected) // baseline vs `migrate diff --from-empty --to-schema-datamodel`That assertion would have failed on your PR and the obvious way to make it green is the regeneration that causes the collision. It now runs the comparison only while the baseline is the whole history, and once there is more than one migration it defers to the DB-backed replay ( I also added a case asserting that no migration sorts before the baseline. Prisma replays lexicographically, so a hand-made folder named 3. The failed write was swallowed} catch {
// Best-effort write: database error updating lastUsedAt should not fail
// an otherwise valid and authenticated request.
return false
}The reasoning is right — refusing a valid authenticated request because an audit timestamp could not be stored would be a bad trade. But after (1), a missing column is a live possibility, and a silent } catch (err: unknown) {
if (!lastUsedWriteFailuresLogged.has(keyId)) {
lastUsedWriteFailuresLogged.add(keyId)
log.warn({ err, keyId }, 'could not record lastUsedAt for an API key; authentication is unaffected')
}
return false
}Once per key rather than once per throttle window, so one misconfigured environment is a handful of lines, not a permanent stream. Two smaller changesWhere the call sits. I moved
126 test files / 1,499 tests pass. |
Summary
lastUsedAt(DateTime? @map("last_used_at")) to theApiKeymodel in Prisma.lastUsedAton successful API key authentication inapiKeyAuthPlugin.KEY_LAST_USED_THROTTLE_SECONDS(defaults to 60 seconds).lastUsedAton key listings via admin-guardedGET /admin/keysand key creation responsePOST /admin/keys.Related issue
Closes #500
Type of change
Checklist
npx tsc --noEmitpassesnpm run buildpasses