- index.ts: compute devBypassActive at startup; skip app.use(oidcAuthMiddleware)
entirely when active so the OIDC guard never runs in local dev
- routes/me.ts: read c.get('user') first; return dev identity directly when
devAuthBypass injected it, bypassing getAuth() and the DB upsert
- auth/devBypass.ts: add ContextVariableMap augmentation for 'user' key;
correct stale comment that claimed getAuth/401 path was still active
77 lines
3.1 KiB
TypeScript
77 lines
3.1 KiB
TypeScript
/**
|
|
* Dev-auth bypass middleware (Pitfall 7 — T-02-01).
|
|
*
|
|
* Active ONLY when DEV_AUTH_BYPASS=true AND NODE_ENV !== 'production'.
|
|
* Injects a fixed dev user into the Hono context so the OIDC auth guard is effectively
|
|
* bypassed for local development WITHOUT live Authelia (D-14).
|
|
*
|
|
* Mount BEFORE oidcAuthMiddleware on /api/* in index.ts.
|
|
* When the bypass is inactive (wrong env, or NODE_ENV=production) the middleware is a
|
|
* pure no-op passthrough — production behaviour is unchanged.
|
|
*
|
|
* Context key: 'user' — matches the key read by downstream consumers.
|
|
* In dev bypass mode, c.get('user') returns DEV_USER. index.ts does NOT mount
|
|
* oidcAuthMiddleware when devBypassActive is true, so getAuth(c) is never called.
|
|
* routes/me.ts reads c.get('user') first and returns the dev identity directly,
|
|
* skipping the DB upsert and getAuth path entirely. Other routes (e.g. events)
|
|
* also read c.get('user') directly — same pattern, no change needed there.
|
|
*
|
|
* Security:
|
|
* - The FIRST conditional is always `NODE_ENV === 'production'` — checked before reading
|
|
* any other env var. This is the hard guard (T-02-01). Even if DEV_AUTH_BYPASS is
|
|
* accidentally set in production config, the guard fires and returns a no-op.
|
|
* - The production Docker Compose MUST NOT set DEV_AUTH_BYPASS. See docs/deployment.md.
|
|
* - This file must never be removed — the pattern is referenced by Plan 02 routes.
|
|
*/
|
|
|
|
import type { MiddlewareHandler } from 'hono'
|
|
import { COLOR_PALETTE } from './user.js'
|
|
|
|
export const DEV_USER = {
|
|
id: 1,
|
|
oidcIss: 'dev',
|
|
oidcSub: 'dev-user',
|
|
displayName: 'Dev User',
|
|
color: COLOR_PALETTE[0], // '#4A90D9' — first palette slot
|
|
} as const
|
|
|
|
/**
|
|
* Extend Hono's ContextVariableMap so that c.get('user') / c.set('user', ...)
|
|
* are statically typed throughout the app. The value type is the DEV_USER shape,
|
|
* which is compatible with both the bypass path and any future app-level user object
|
|
* stored on context (they share the same id/displayName/color subset).
|
|
*/
|
|
declare module 'hono' {
|
|
interface ContextVariableMap {
|
|
user: typeof DEV_USER
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a Hono MiddlewareHandler that injects DEV_USER into the request context
|
|
* when the dev-auth bypass is active, or a pure passthrough when inactive.
|
|
*
|
|
* The function evaluates env vars at call time (when the app starts), not at request time.
|
|
* This means the middleware choice is fixed for the lifetime of the process — intentional,
|
|
* since changing auth mode requires a restart.
|
|
*/
|
|
export function devAuthBypass(): MiddlewareHandler {
|
|
// Hard production guard — FIRST check, before reading any other env var.
|
|
// Ensures this middleware can never grant access in production regardless of config.
|
|
if (process.env.NODE_ENV === 'production') {
|
|
return async (_c, next) => next()
|
|
}
|
|
|
|
// Bypass flag not set — passthrough; OIDC auth proceeds normally.
|
|
if (process.env.DEV_AUTH_BYPASS !== 'true') {
|
|
return async (_c, next) => next()
|
|
}
|
|
|
|
// Bypass active: inject fixed dev user into Hono context.
|
|
// Routes that read c.get('user') will receive DEV_USER.
|
|
return async (c, next) => {
|
|
c.set('user', DEV_USER)
|
|
await next()
|
|
}
|
|
}
|