Add API key authentication for programmatic access
- New ApiKey model in Prisma schema (tenant + user scoped) - Keys are SHA-256 hashed, only shown once on creation - Bearer token auth in hooks.server.ts (alongside session cookies) - CRUD endpoint at /api/account/api-keys (max 10 per user) - Keys prefixed with pnc_ for easy identification Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import bcrypt from 'bcrypt';
|
||||
import crypto from 'crypto';
|
||||
import { prisma } from './db.js';
|
||||
import { withBypassRLS } from './rls.js';
|
||||
|
||||
@@ -70,3 +71,46 @@ export function sessionCookieOptions(expiresAt: Date) {
|
||||
expires: expiresAt
|
||||
};
|
||||
}
|
||||
|
||||
// ─── API Keys ────────────────────────────────────────────────
|
||||
|
||||
export function hashApiKey(key: string): string {
|
||||
return crypto.createHash('sha256').update(key).digest('hex');
|
||||
}
|
||||
|
||||
export function generateApiKey(): { key: string; prefix: string } {
|
||||
const key = `pnc_${crypto.randomBytes(32).toString('hex')}`;
|
||||
const prefix = key.slice(0, 12);
|
||||
return { key, prefix };
|
||||
}
|
||||
|
||||
export async function validateApiKey(key: string) {
|
||||
const keyHash = hashApiKey(key);
|
||||
|
||||
const apiKey = await prisma.apiKey.findUnique({
|
||||
where: { keyHash },
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
name: true,
|
||||
globalRole: true,
|
||||
tenantRole: true,
|
||||
tenantId: true,
|
||||
avatarUrl: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!apiKey) return null;
|
||||
|
||||
// Update last used timestamp (fire and forget)
|
||||
prisma.apiKey.update({
|
||||
where: { id: apiKey.id },
|
||||
data: { lastUsedAt: new Date() }
|
||||
}).catch(() => {});
|
||||
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user