Phase 2: Microsoft Entra ID (OIDC) provider

↗ view on GitHub · Claude · 2026-05-15 · 0ba2ba0d

Adds Entra OIDC as a second auth provider alongside Credentials. The
provider is enabled only when all three AUTH_MICROSOFT_ENTRA_ID_*
environment variables are set on the frontend; otherwise the
Credentials path remains and the login page omits the button.

Backend:
- New POST /auth/oidc-link route. Called server-to-server from the
  frontend Auth.js jwt callback after a successful Entra exchange.
  Authenticated by the shared AUTH_SECRET in the X-Internal-Auth
  header via timingSafeEqual.
- New upsertEntraUser helper. Looks up by entra_subject; falls back
  to email match (linking a Credentials user to their Entra identity
  by setting entra_subject); creates a new row otherwise. Rejects
  disallowed domains (org_settings.allowed_email_domains), disabled
  accounts, and email/subject conflicts (409). Applies the
  BOOTSTRAP_ADMIN_EMAIL promotion. Emits user.register.oidc on first
  sign-in and user.login.oidc on every sign-in.

Frontend:
- auth.ts: conditionally adds the MicrosoftEntraID provider when
  AUTH_MICROSOFT_ENTRA_ID_ID, _SECRET, and _TENANT_ID are all set.
  Exports isEntraConfigured.
- jwt callback detects account.provider === "microsoft-entra-id" and
  calls /auth/oidc-link; on success copies id, email, role,
  onboarded into the session token. On failure returns an empty
  token so the session does not persist.
- New GET /api/auth/providers-config route reports provider
  availability without exposing any secret.
- Login page fetches /api/auth/providers-config and renders a
  "Sign in with Microsoft" button when configured. Clicking it calls
  signIn("microsoft-entra-id", { callbackUrl }).

End-to-end verification against Postgres 16:
- Missing X-Internal-Auth returns 403.
- Wrong X-Internal-Auth returns 403 (timing-safe compare).
- First Entra sign-in promotes BOOTSTRAP_ADMIN_EMAIL to admin.
- Second sign-in same subject is idempotent.
- Disallowed domain returns 400 with clear message.
- Credentials user signing in via Entra links automatically.
- Same email with different Entra subject returns 409.
- Audit log records user.register.oidc and user.login.oidc.

Docs:
- docs/developer/07-auth.md: new Entra section with flow, redirect
  URI requirements, and the full env-var table.
- frontend/.env.local.example documents the three new variables.
- CHANGELOG.md and Instructions.md updated.
Repository cpatpa/PIP
Author Claude <noreply@anthropic.com>
Authored
Parents d384aee8
Stats 9 files changed , +433 , -7
Part of Phase 2 - Auth.js v5 + Entra OIDC + password reset

Capture this commit into my fork

Download a Markdown prompt that tells Claude how to port this exact commit into your working tree. Run it via claude -p < capture-commit-0ba2ba0d.md from inside the repo you want the change in.

⬇ Download capture-commit-0ba2ba0d.md