import { createHash } from 'node:crypto'; import type { MiddlewareHandler } from 'hono'; import { lookupApiKey, type ApiKeyLookup } from './db'; export interface AuthVars { apiKey: ApiKeyLookup; } function sha256Hex(input: string): string { return createHash('sha256').update(input).digest('hex'); } /** * Hono middleware: require a valid `Authorization: Bearer ti_...` header. * On success, attaches the resolved ApiKeyLookup to c.var.apiKey so the * handler can see the caller's account + plan + key. */ export const auth: MiddlewareHandler<{ Variables: AuthVars }> = async ( c, next ) => { const header = c.req.header('authorization') ?? c.req.header('Authorization'); if (!header) { return c.json({ error: 'Missing Authorization header' }, 401); } const match = /^Bearer\s+(\S+)$/i.exec(header); if (!match) { return c.json( { error: 'Authorization header must be `Bearer `' }, 401 ); } const token = match[1]!; if (!token.startsWith('ti_')) { return c.json({ error: 'Invalid API key format' }, 401); } const key = lookupApiKey(sha256Hex(token)); if (!key) { return c.json({ error: 'Invalid or revoked API key' }, 401); } c.set('apiKey', key); return next(); };