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:
parent
0b8812d864
commit
21175c5b7a
14 changed files with 373 additions and 527 deletions
|
|
@ -1,168 +1,99 @@
|
|||
# Local development setup with Authentik OIDC provider and Heady client
|
||||
# Uses caddy-docker-proxy for automatic TLS and routing
|
||||
# Minimal Authentik stack for local Heady auth testing.
|
||||
# Heady itself runs natively via `npm run dev`; this stack only provides
|
||||
# the OIDC provider it talks to.
|
||||
|
||||
services:
|
||||
# PostgreSQL for Authentik
|
||||
postgresql:
|
||||
heady-postgres:
|
||||
image: docker.io/library/postgres:15-alpine
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
|
||||
test: ['CMD-SHELL', 'pg_isready -d authentik -U authentik']
|
||||
start_period: 20s
|
||||
interval: 30s
|
||||
retries: 5
|
||||
timeout: 5s
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- heady_postgres_data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${PG_PASS:-authentik-postgres-password}
|
||||
POSTGRES_USER: ${PG_USER:-authentik}
|
||||
POSTGRES_DB: ${PG_DB:-authentik}
|
||||
env_file:
|
||||
- .env.local
|
||||
networks:
|
||||
- authentik-internal
|
||||
POSTGRES_PASSWORD: authentik-local-pw
|
||||
POSTGRES_USER: authentik
|
||||
POSTGRES_DB: authentik
|
||||
networks: [authentik-internal]
|
||||
|
||||
# Redis for Authentik
|
||||
redis:
|
||||
heady-redis:
|
||||
image: docker.io/library/redis:alpine
|
||||
command: --save 60 1 --loglevel warning
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||
test: ['CMD-SHELL', 'redis-cli ping | grep PONG']
|
||||
start_period: 20s
|
||||
interval: 30s
|
||||
retries: 5
|
||||
timeout: 3s
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- authentik-internal
|
||||
- heady_redis_data:/data
|
||||
networks: [authentik-internal]
|
||||
|
||||
# Authentik Server
|
||||
authentik-server:
|
||||
image: ghcr.io/goauthentik/authentik:2024.8.3
|
||||
heady-authentik-server:
|
||||
image: ghcr.io/goauthentik/server:2024.12
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS:-authentik-postgres-password}
|
||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-super-secret-authentik-key-change-me}
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED: false
|
||||
AUTHENTIK_DISABLE_UPDATE_CHECK: true
|
||||
AUTHENTIK_DISABLE_STARTUP_ANALYTICS: true
|
||||
AUTHENTIK_REDIS__HOST: heady-redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: heady-postgres
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: authentik-local-pw
|
||||
AUTHENTIK_SECRET_KEY: heady-local-authentik-secret-key-2026
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED: 'false'
|
||||
AUTHENTIK_DISABLE_UPDATE_CHECK: 'true'
|
||||
AUTHENTIK_DISABLE_STARTUP_ANALYTICS: 'true'
|
||||
AUTHENTIK_AVATARS: initials
|
||||
volumes:
|
||||
- authentik_media:/media
|
||||
- authentik_custom-templates:/templates
|
||||
env_file:
|
||||
- .env.local
|
||||
depends_on:
|
||||
- postgresql
|
||||
- redis
|
||||
networks:
|
||||
- caddy
|
||||
- authentik-internal
|
||||
- heady_authentik_media:/media
|
||||
- heady_authentik_templates:/templates
|
||||
# Auto-load custom blueprints (Heady OIDC provider + application).
|
||||
# Anything in /blueprints/* is reconciled on startup.
|
||||
- ./authentik-blueprints:/blueprints/heady:ro
|
||||
depends_on: [heady-postgres, heady-redis]
|
||||
networks: [caddy, authentik-internal]
|
||||
labels:
|
||||
caddy: auth.l.supported.systems
|
||||
caddy.reverse_proxy: "{{upstreams 9000}}"
|
||||
caddy.tls: internal
|
||||
caddy: heady-auth.l.supported.systems
|
||||
caddy.reverse_proxy: '{{upstreams 9000}}'
|
||||
|
||||
# Authentik Worker
|
||||
authentik-worker:
|
||||
image: ghcr.io/goauthentik/authentik:2024.8.3
|
||||
heady-authentik-worker:
|
||||
image: ghcr.io/goauthentik/server:2024.12
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: postgresql
|
||||
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS:-authentik-postgres-password}
|
||||
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-super-secret-authentik-key-change-me}
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED: false
|
||||
AUTHENTIK_DISABLE_UPDATE_CHECK: true
|
||||
AUTHENTIK_DISABLE_STARTUP_ANALYTICS: true
|
||||
AUTHENTIK_REDIS__HOST: heady-redis
|
||||
AUTHENTIK_POSTGRESQL__HOST: heady-postgres
|
||||
AUTHENTIK_POSTGRESQL__USER: authentik
|
||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||
AUTHENTIK_POSTGRESQL__PASSWORD: authentik-local-pw
|
||||
AUTHENTIK_SECRET_KEY: heady-local-authentik-secret-key-2026
|
||||
AUTHENTIK_ERROR_REPORTING__ENABLED: 'false'
|
||||
AUTHENTIK_DISABLE_UPDATE_CHECK: 'true'
|
||||
AUTHENTIK_DISABLE_STARTUP_ANALYTICS: 'true'
|
||||
user: root
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- authentik_media:/media
|
||||
- authentik_certs:/certs
|
||||
- authentik_custom-templates:/templates
|
||||
env_file:
|
||||
- .env.local
|
||||
depends_on:
|
||||
- postgresql
|
||||
- redis
|
||||
networks:
|
||||
- authentik-internal
|
||||
|
||||
# Heady Application (Development)
|
||||
heady-dev:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.dev
|
||||
target: development
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# Astro dev server config
|
||||
HOST: "0.0.0.0"
|
||||
PORT: "3000"
|
||||
|
||||
# OIDC Configuration
|
||||
AUTHENTIK_ISSUER: "https://auth.l.supported.systems/application/o/heady/"
|
||||
AUTHENTIK_CLIENT_ID: "heady-local-test"
|
||||
AUTHENTIK_CLIENT_SECRET: "your-client-secret-here"
|
||||
PUBLIC_URL: "https://heady.l.supported.systems"
|
||||
|
||||
# Session Configuration
|
||||
SESSION_SECRET: "this-is-a-32-char-session-secret-key!"
|
||||
SESSION_LIFETIME: "24h"
|
||||
|
||||
# Role Mapping
|
||||
HEADY_OWNER_GROUPS: "founders,ceo,executives"
|
||||
HEADY_ADMIN_GROUPS: "admin,administrators,managers"
|
||||
HEADY_NETWORK_GROUPS: "devops,network,sre,infrastructure"
|
||||
HEADY_IT_GROUPS: "helpdesk,support,it-support"
|
||||
HEADY_AUDITOR_GROUPS: "audit,auditor,compliance,security"
|
||||
|
||||
# Development Mode
|
||||
NODE_ENV: "development"
|
||||
HEADY_LOAD_ENV_OVERRIDES: "true"
|
||||
volumes:
|
||||
- .:/app
|
||||
- /app/node_modules
|
||||
env_file:
|
||||
- .env.local
|
||||
depends_on:
|
||||
- authentik-server
|
||||
networks:
|
||||
- caddy
|
||||
labels:
|
||||
caddy: heady.l.supported.systems
|
||||
caddy.reverse_proxy: "{{upstreams 3000}}"
|
||||
caddy.tls: internal
|
||||
# HMR WebSocket support for Astro/Vite
|
||||
caddy.reverse_proxy.flush_interval: "-1"
|
||||
caddy.reverse_proxy.transport: "http"
|
||||
caddy.reverse_proxy.transport.read_timeout: "0"
|
||||
caddy.reverse_proxy.transport.write_timeout: "0"
|
||||
caddy.reverse_proxy.transport.keepalive: "5m"
|
||||
caddy.reverse_proxy.stream_timeout: "24h"
|
||||
caddy.reverse_proxy.stream_close_delay: "5s"
|
||||
- heady_authentik_media:/media
|
||||
- heady_authentik_certs:/certs
|
||||
- heady_authentik_templates:/templates
|
||||
- ./authentik-blueprints:/blueprints/heady:ro
|
||||
depends_on: [heady-postgres, heady-redis]
|
||||
networks: [authentik-internal]
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
authentik_media:
|
||||
authentik_certs:
|
||||
authentik_custom-templates:
|
||||
heady_postgres_data:
|
||||
heady_redis_data:
|
||||
heady_authentik_media:
|
||||
heady_authentik_certs:
|
||||
heady_authentik_templates:
|
||||
|
||||
networks:
|
||||
caddy:
|
||||
external: true
|
||||
authentik-internal:
|
||||
driver: bridge
|
||||
driver: bridge
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue