feat(auth): Entra ID provider with JWKS + tenant lifecycle + roles
Adds the Entra branch of the auth boundary established in the previous
refactor. Components:
* lib/auth/providers/entra.ts - JWT validation against the tenant's
JWKS (5-minute cache), with both v1.0 and v2.0 issuer + audience
shapes accepted, exp/nbf checks, and a fallback chain for the
email and display-name claims that Entra optionally populates.
* lib/auth/roles.ts - Maps Entra group OIDs to app roles
via ENTRA_ADMIN_GROUP_IDS / ENTRA_MEMBER_GROUP_IDS env vars.
TenantAdmin includes Member by inheritance.
* middleware/tenantAccess.ts - Entra-only tenant lifecycle: looks
up the principal's tenant in the tenants table, denies UNKNOWN /
PENDING / SUSPENDED tenants, and enforces group-to-role mapping.
Auto-onboards when TENANT_ONBOARDING_MODE=auto. No-ops for any
other auth provider so non-Entra deployments are unaffected.
* middleware/requireRole.ts - Tiny role guard that 403s when the
principal lacks the requested role.
* Auth middleware now dispatches "entra" alongside "supabase" and
routes every authenticated request through tenantAccess (no-op for
non-Entra) after upserting the user_profiles row from the IdP
claims. upsertUserProfile back-fills display_name only when null
so the user's own edits aren't clobbered on every request.
| Repository | Altien/mikeOssAzure |
|---|---|
| Author | Allen Morgan <amorgan@altien.com> |
| Authored | |
| Parents | b9f5f60a |
| Stats | 6 files changed , +426 , -1 |
| Part of | Auth provider abstraction (Supabase / Entra / local HS256) |
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-f9eb061c.md
from inside the repo you want the change in.