auth: stateless PKCE state, simplify OIDC handlers

- src/lib/auth/oidc-state.ts (new): pack {state, codeVerifier} into a
  short-lived signed JWT, store in an httpOnly cookie. Replaces the
  process-local Map that broke under multi-worker deployments where
  /api/auth/login and /api/auth/callback would land on different workers.
- src/pages/api/auth/{login,callback,logout,profile,status}.ts: drop the
  Map-based state-store calls; use oidc-state for set/get/clear.
- src/lib/auth/oidc-client.ts, session-manager.ts, config/authentik.ts:
  small adjustments to fit the new state surface.
- src/components/auth/AuthenticatedLayout.astro, src/layouts/Layout.astro:
  trim a lot of layout boilerplate (~125 lines each).
- astro.config.mjs, docker-compose.local.yml: minor cleanup.
- authentik-blueprints/heady-oidc.yaml (new): declarative provider +
  application blueprint to ship alongside Heady deployments.
This commit is contained in:
Ryan Malloy 2026-06-06 14:11:51 -06:00
parent 0b8812d864
commit 21175c5b7a
14 changed files with 373 additions and 527 deletions

View file

@ -26,20 +26,13 @@ export default defineConfig({
include: ['alpinejs', 'guacamole-lite', 'chart.js'],
},
server: {
proxy: {
// Proxy API calls to Go backend during development
// Exclude auth endpoints to test our new OIDC system
'/api/(?!auth).*': {
target: 'http://localhost:3000',
changeOrigin: true,
},
// Proxy remote access calls to FastAPI
'/terminal': {
target: 'http://localhost:8000',
changeOrigin: true,
ws: true, // Enable WebSocket proxying
},
},
// No proxy rules: Vite proxy `key` strings are treated as prefix
// matches (not regex) by default, so a pattern like
// `/api/(?!auth).*` was matching `/api/auth/login` literally and
// 404-proxying it to a non-existent backend. The Astro/Astro-only
// auth endpoints under /api/auth/* must reach Astro's SSR handler
// directly. Add proxies back per-route (using `^` prefix for
// regex) once a real backend exists.
},
},