This commit adds the initial technical plan for the 063-entra-signin feature. The plan outlines the high-level architecture, key components, database changes, test plan, and deployment considerations based on the clarified feature specification. The plan addresses: - Authentication flow via Laravel Socialite and Entra ID. - User provisioning and upsert logic. - Post-login routing based on tenant memberships, including a dedicated chooser page for multiple memberships. - Handling of disabled user logins. - Database schema details for Entra ID fields. - Comprehensive test coverage using Pest (unit, feature, browser tests).
6.7 KiB
6.7 KiB
Technical Plan: 063 — Entra Sign-in (Tenant Panel) v1
Feature Branch: 063-entra-signin
Created: 2026-01-26
Status: Draft (v1)
Spec: specs/063-entra-signin/spec.md
1. Overview & Goal Alignment
- Goal: Implement a secure, Entra ID-only sign-in flow for the Tenant Admin panel (
/admin), safely onboarding users and routing them based on tenant memberships. - Key Constraints: No
/systempanel modification, no Graph calls during render/hydration, DB-only at render time for login/no-access pages, synchronous login flow. - Clarifications Incorporated:
- Multi-tenant users redirect to a dedicated chooser page.
- Disabled users are blocked from login, redirected to
/admin/loginwith generic error. entra_tenant_idandentra_object_idcolumns areVARCHAR(36)(or UUID for Postgres).
2. Architecture & High-Level Design
- Authentication Flow:
- User navigates to
/admin/login. - Presented with "Sign in with Microsoft" button (no local login fields).
- Clicking button initiates OIDC flow via Laravel Socialite (Entra ID provider).
- Redirects to
/auth/entra/redirect. - Entra ID authenticates user and redirects back to
/auth/entra/callbackwith OIDC claims. - Callback handler:
- Validates claims (
tid,oidpresent). - Performs upsert on
userstable based on(entra_tenant_id, entra_object_id). - Checks user status (active/disabled). If disabled, blocks login.
- Regenerates session.
- Determines post-login route based on tenant memberships.
- Validates claims (
- User navigates to
- User Provisioning (Upsert):
- Use
User::updateOrCreatewith['entra_tenant_id' => $tid, 'entra_object_id' => $oid]as unique key. - Populate
name,emailfrom claims. entra_tenant_id,entra_object_idcolumns asVARCHAR(36)(or UUID).
- Use
- Post-Login Routing:
- 0 Memberships: Redirect to
/admin/no-access(Filament page). - 1 Membership: Redirect to that tenant’s dashboard.
- N Memberships: Redirect to
/admin/choose-tenant(dedicated Filament chooser page).
- 0 Memberships: Redirect to
- Session Separation: Leverage Laravel's guard system for clear separation between
platform(system) andtenant(admin) panels.
3. Key Components & Implementation Details
- Laravel Socialite:
- Configure Entra ID provider in
config/services.php. - Create
SocialiteController(or similar) to handle/auth/entra/redirectand/auth/entra/callback.
- Configure Entra ID provider in
- User Model (
app/Models/User.php):- Add
entra_tenant_idandentra_object_idas fillable properties. - Implement logic for checking
tenants()relationship.
- Add
- Migrations:
- Add
entra_tenant_id(string('entra_tenant_id', 36)->nullable()oruuid('entra_tenant_id')) andentra_object_id(string('entra_object_id', 36)->nullable()oruuid('entra_object_id')) columns touserstable. - Add unique index
unique(['entra_tenant_id', 'entra_object_id']). - Note: Initial migration can add as nullable, then a follow-up migration can make non-nullable if all existing users are migrated or it's a new system. Given it's a new system for
adminsign-in, it should probably be non-nullable from the start.
- Add
- Filament Panel Customization:
- Override default Filament login page for
/adminpanel to remove email/password fields and add "Sign in with Microsoft" button. - Create
NoAccessPage(/admin/no-access) andTenantChooserPage(/admin/choose-tenant) as Filament pages.
- Override default Filament login page for
- Error Handling & Logging:
- Implement robust OIDC failure handling as per
FR-004. - Utilize Laravel's logging facilities for privacy-safe audit logs (
FR-005). - Define stable
reason_codeexamples (e.g.,oidc_missing_claims,user_disabled).
- Implement robust OIDC failure handling as per
- Service Layer (Optional but Recommended):
- Consider a
EntraLoginServiceto encapsulate OIDC callback logic, user upsert, and routing decisions. This keeps controllers lean and business logic testable.
- Consider a
4. Database Schema Changes
userstable:entra_tenant_idstring('entra_tenant_id', 36)->nullable()(oruuid('entra_tenant_id'))entra_object_idstring('entra_object_id', 36)->nullable()(oruuid('entra_object_id'))- Add
unique(['entra_tenant_id', 'entra_object_id'])index. - Note: Initial migration can add as nullable, then a follow-up migration can make non-nullable if all existing users are migrated or it's a new system. Given it's a new system for
adminsign-in, it should probably be non-nullable from the start.
5. Test Plan (Building on Spec Acceptance Tests)
- Unit Tests (Pest):
- Socialite callback handler logic (claim validation, upsert logic, disabled user check).
- User model methods related to Entra ID and tenant memberships.
- Routing service/resolver.
- Feature Tests (Pest):
AdminLoginIsEntraOnlyTest(GET/admin/loginrenders correctly, no password inputs).EntraCallbackUpsertByTidOidTest(callback upserts, session regenerated).PostLoginRoutingByMembershipTest(0, 1, N memberships routing).OidcFailureRedirectsSafelyTest(missing claims, generic error, logs).SessionSeparationSmokeTest(guard separation works).DisabledUserLoginIsBlockedTest(disabled user login attempt blocked and logged).
- Browser Tests (Pest v4):
- End-to-end flow for successful Entra login.
- Verify the
/admin/choose-tenantpage renders correctly and allows selection.
6. Deployment Considerations
- Environment Variables:
ENTRA_CLIENT_ID,ENTRA_CLIENT_SECRET,ENTRA_REDIRECT_URIfor Socialite.- These must be managed securely (Dokploy environment variables).
- Migrations: Ensure database migrations are run (
sail artisan migrate). - Filament Assets:
php artisan filament:assetsmust be run on deployment. - Dokploy: Ensure Dokploy config includes any new routes/pages.
7. Open Questions / Potential Risks
- Entra ID Setup: Assumed Entra ID application registration and configuration are handled externally.
last_tenant_id: Decision on whether to implementlast_tenant_idfor multi-membership users is deferred. It's an optimization.- User Provisioning: What if required claims like
emailornameare missing from Entra ID? Current spec implies they should be present, but fallback behavior is not explicitly defined forname(email is nullable). - Authorization: This plan focuses on authentication. Tenant-specific authorization (what actions a user can perform within a tenant) is out of scope for this feature (covered by
062-tenant-rbac-v1).