Phase 2: Microsoft Entra ID (OIDC) provider
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.