diff options
| author | benj <benj@rse8.com> | 2026-05-01 09:36:21 +0800 |
|---|---|---|
| committer | benj <benj@rse8.com> | 2026-05-01 09:36:21 +0800 |
| commit | 850f4f826b536d913235e174dc07aef74e51bf60 (patch) | |
| tree | a2806da6c0ed5c48d21178e0c6c280d5a40ccd38 /web/api/src/auth.ts | |
| parent | 6605e2cc428e3bdaa174ccc432941eab8c5d61cb (diff) | |
| download | tidyindex-850f4f826b536d913235e174dc07aef74e51bf60.tar tidyindex-850f4f826b536d913235e174dc07aef74e51bf60.tar.gz tidyindex-850f4f826b536d913235e174dc07aef74e51bf60.tar.bz2 tidyindex-850f4f826b536d913235e174dc07aef74e51bf60.tar.lz tidyindex-850f4f826b536d913235e174dc07aef74e51bf60.tar.xz tidyindex-850f4f826b536d913235e174dc07aef74e51bf60.tar.zst tidyindex-850f4f826b536d913235e174dc07aef74e51bf60.zip | |
Diffstat (limited to 'web/api/src/auth.ts')
| -rw-r--r-- | web/api/src/auth.ts | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/web/api/src/auth.ts b/web/api/src/auth.ts new file mode 100644 index 0000000..d22f26d --- /dev/null +++ b/web/api/src/auth.ts @@ -0,0 +1,49 @@ +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 <api_key>`' }, + 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(); +}; |
