feat(auth): Entra ID provider with JWKS + tenant lifecycle + roles

↗ view on GitHub · Allen Morgan · 2026-05-08 · f9eb061c

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.

⬇ Download capture-commit-f9eb061c.md