feat: add scoped API keys for programmatic site access

Introduce ApiKey model, CRUD endpoints, and admin UI so agents can
authenticate with permission-scoped keys. Normalize pubkeys to hex on login,
dedupe legacy npub/hex user rows, and ignore .cursor in git.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
bbe
2026-06-23 09:29:30 +02:00
co-authored by Cursor
parent 70e3e0633d
commit a6a2b113ee
17 changed files with 836 additions and 100 deletions
@@ -0,0 +1,15 @@
-- CreateTable
CREATE TABLE "ApiKey" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"prefix" TEXT NOT NULL,
"keyHash" TEXT NOT NULL,
"permissions" TEXT NOT NULL,
"createdByPubkey" TEXT NOT NULL,
"lastUsedAt" DATETIME,
"revokedAt" DATETIME,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- CreateIndex
CREATE UNIQUE INDEX "ApiKey_keyHash_key" ON "ApiKey"("keyHash");
+15
View File
@@ -17,6 +17,21 @@ model User {
updatedAt DateTime @updatedAt
}
// Scoped API key for programmatic access. The raw key is shown to the creator
// only once; only its SHA-256 hash is stored. `permissions` is a JSON array of
// permission keys that gate what the key may do.
model ApiKey {
id String @id @default(uuid())
name String
prefix String // leading characters of the raw key, for display
keyHash String @unique // SHA-256 hex of the full key
permissions String // JSON array of permission keys
createdByPubkey String
lastUsedAt DateTime?
revokedAt DateTime?
createdAt DateTime @default(now())
}
// Maps an assignable role to a granted permission key. Editable at runtime.
// One row per (role, permission). SuperAdmin is never stored here; it bypasses
// all checks via the env list.