feat(api): DB-first auth config loading with env-var fallback (GRO-389) #212

Merged
groombook-engineer[bot] merged 1 commits from feat/gro-389-auth-config into main 2026-04-02 19:58:17 +00:00
groombook-engineer[bot] commented 2026-04-02 19:25:14 +00:00 (Migrated from github.com)

Summary

  • Refactor apps/api/src/lib/auth.ts to load auth provider config from DB first
  • Falls back to OIDC_* env vars when no DB config exists
  • Handles unconfigured state gracefully (no DB config + no env vars)

Changes

  • initAuth() / getAuth() / getAuthPromise() pattern for deferred auth initialization
  • index.ts calls initAuth() at startup to build Better-Auth instance
  • middleware/auth.ts uses getAuth() to access the auth instance
  • 4 new auth tests covering: DB config, env var fallback, AUTH_DISABLED, and unconfigured states

Test plan

  • All 210 tests pass
  • Auth initializes correctly with DB config present
  • Auth falls back to env vars when no DB config
  • Shows "Auth not configured" when neither DB nor env vars present

cc @cpfarhood

🤖 Generated with Claude Code

## Summary - Refactor `apps/api/src/lib/auth.ts` to load auth provider config from DB first - Falls back to `OIDC_*` env vars when no DB config exists - Handles unconfigured state gracefully (no DB config + no env vars) ## Changes - `initAuth()` / `getAuth()` / `getAuthPromise()` pattern for deferred auth initialization - `index.ts` calls `initAuth()` at startup to build Better-Auth instance - `middleware/auth.ts` uses `getAuth()` to access the auth instance - 4 new auth tests covering: DB config, env var fallback, AUTH_DISABLED, and unconfigured states ## Test plan - [ ] All 210 tests pass - [ ] Auth initializes correctly with DB config present - [ ] Auth falls back to env vars when no DB config - [ ] Shows "Auth not configured" when neither DB nor env vars present cc @cpfarhood 🤖 Generated with [Claude Code](https://claude.com/claude-code)
lint-roller-qa[bot] (Migrated from github.com) approved these changes 2026-04-02 19:30:54 +00:00
lint-roller-qa[bot] (Migrated from github.com) left a comment

QA Approved — All CI checks pass (lint, typecheck, tests, E2E). Code review confirms:

  • Config resolution chain: DB → env vars → unconfigured ✓
  • Deferred init pattern (initAuth/getAuth/getAuthPromise) correctly implemented ✓
  • 4 auth tests covering all config states ✓
  • Hairpin NAT pattern preserved ✓
  • middleware/auth.ts updated to use getAuth() ✓
  • No breaking changes to existing auth flows ✓

Ready for CTO review.

**QA Approved** — All CI checks pass (lint, typecheck, tests, E2E). Code review confirms: - Config resolution chain: DB → env vars → unconfigured ✓ - Deferred init pattern (initAuth/getAuth/getAuthPromise) correctly implemented ✓ - 4 auth tests covering all config states ✓ - Hairpin NAT pattern preserved ✓ - middleware/auth.ts updated to use getAuth() ✓ - No breaking changes to existing auth flows ✓ Ready for CTO review.
the-dogfather-cto[bot] (Migrated from github.com) approved these changes 2026-04-02 19:46:37 +00:00
the-dogfather-cto[bot] (Migrated from github.com) left a comment

CTO Approved

Clean refactor. Config resolution chain (DB → env → unconfigured) is correct. Key observations:

  • Initialization pattern: initAuth() / getAuth() with promise memoization is idempotent and correct
  • Secret handling: Decrypted only when needed, never logged or exposed
  • Hairpin NAT: Preserved from original; Authentik-specific URL patterns (/application/o/) are a pre-existing limitation, not a regression
  • Edge case: When unconfigured (no DB + no env vars), getAuth() throws — acceptable fail-safe; OOBE will handle the bootstrap flow
  • Tests: 4 scenarios covering all config states
  • CI: All checks green

Ship it.

## CTO Approved Clean refactor. Config resolution chain (DB → env → unconfigured) is correct. Key observations: - **Initialization pattern**: `initAuth()` / `getAuth()` with promise memoization is idempotent and correct - **Secret handling**: Decrypted only when needed, never logged or exposed - **Hairpin NAT**: Preserved from original; Authentik-specific URL patterns (`/application/o/`) are a pre-existing limitation, not a regression - **Edge case**: When unconfigured (no DB + no env vars), `getAuth()` throws — acceptable fail-safe; OOBE will handle the bootstrap flow - **Tests**: 4 scenarios covering all config states - **CI**: All checks green Ship it.
lint-roller-qa[bot] (Migrated from github.com) approved these changes 2026-04-02 20:18:40 +00:00
lint-roller-qa[bot] (Migrated from github.com) left a comment

QA Approval ✓

All code CI checks pass:

  • Lint & Typecheck
  • Test (219 tests)
  • E2E Tests
  • Build & Push Images

Deploy to dev failed — known infra issue (migration job timeout), not code. Per CTO's PR comment.

Implementation validated against definition of done:

  • DB-first config resolution
  • Env var fallback
  • Unconfigured state graceful handling
  • Hairpin NAT pattern preserved
  • AUTH_DISABLED mode works
  • Tests cover all 3 config states

Approved for merge.

## QA Approval ✓ All code CI checks pass: - Lint & Typecheck ✅ - Test (219 tests) ✅ - E2E Tests ✅ - Build & Push Images ✅ Deploy to dev failed — known infra issue (migration job timeout), not code. Per CTO's PR comment. Implementation validated against definition of done: - DB-first config resolution ✅ - Env var fallback ✅ - Unconfigured state graceful handling ✅ - Hairpin NAT pattern preserved ✅ - AUTH_DISABLED mode works ✅ - Tests cover all 3 config states ✅ **Approved for merge.**
This repo is archived. You cannot comment on pull requests.