4.9 KiB
Implementation Plan: 063 — Entra Sign-in (Tenant Panel) v1
Branch: 063-entra-signin | Date: 2026-01-27 | Spec: specs/063-entra-signin/spec.md
Input: Feature specification from /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/063-entra-signin/spec.md
Summary
This feature will implement Microsoft Entra ID OIDC-based sign-in for the Tenant Admin panel. The implementation will override the default Filament login page to present an Entra-only sign-in option. It will utilize Laravel Socialite to manage the OAuth2 flow, handling redirection to Microsoft Entra ID and processing the callback. Core logic involves upserting users based on (entra_tenant_id, entra_object_id), blocking disabled users, regenerating sessions, and dynamically routing users post-login to their tenant dashboard, a dedicated tenant chooser page (for multiple memberships), or a "no access" page (for zero memberships). The implementation adheres to security best practices by not storing sensitive tokens and ensures all affected pages remain DB-only at render time.
Routing stability rule: redirects into a tenant MUST use Filament page URL helpers (e.g., App\\Filament\\Pages\\TenantDashboard::getUrl(tenant: $tenant)) rather than hardcoding /admin/t/..., so future route prefix / tenant slug changes don’t break auth flows.
Technical Context
Language/Version: PHP 8.4
Primary Dependencies: laravel/framework:^12, livewire/livewire:^4, filament/filament:^5, laravel/socialite:^5.0
Storage: PostgreSQL
Testing: Pest
Target Platform: Web
Project Type: Web application
Performance Goals: Callback returns within ~2s under normal conditions.
Constraints: Do not persist secrets/tokens. Sanitize all error output and logs. Outbound HTTP is permitted only inside /auth/entra/* endpoints.
Scale/Scope: Tenant Admin panel (/admin) sign-in only.
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
- Inventory-first: Not directly applicable to auth.
- Read/write separation: N/A for login, but user upsert is a write. The spec requires it to be idempotent, which aligns.
- Graph contract path: The spec explicitly forbids Graph calls during render/poll/hydration, and limits OIDC calls to the
/auth/entra/*routes. This is compliant. - Deterministic capabilities: N/A.
- Tenant isolation: Compliant. The entire flow is built around tenant context (
tid). - Run observability: Compliant. The spec references
OPS-EX-AUTH-001, the Auth Handshake Exception, which exempts this synchronous login flow from requiring anOperationRun. Logging requirements are specified. - Automation: N/A.
- Data minimization: Compliant. Spec says "MUST NOT store Entra access/refresh tokens" and requires safe logging.
- Badge semantics (BADGE-001): N/A.
Result: The plan is compliant with the constitution.
Project Structure
Documentation (this feature)
specs/063-entra-signin/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│ └── entra-auth-flow.md
└── tasks.md
Source Code (repository root)
# Web application
app/
├── Http/
│ ├── Controllers/
│ │ └── Auth/
│ │ └── EntraController.php # New: Handles OIDC redirect and callback logic
│ └── Middleware/
├── Filament/
│ ├── Pages/
│ │ ├── Auth/
│ │ │ └── Login.php # New: Custom Filament login page with Entra-only CTA
│ │ ├── NoAccess.php # New: Page for users with no tenant memberships
│ │ └── ChooseTenant.php # New: Page for users with multiple tenant memberships
│ └── Tenant/
│ └── Resources/
├── Models/
│ └── User.php # Modified: User model for Entra IDs and tenant relationships
├── Providers/
│ └── Filament/
│ └── AdminPanelProvider.php # Modified: Register custom login page
config/
├── services.php # Modified: Add Microsoft Socialite provider config
routes/
│ └── web.php # Modified: Register OIDC redirect and callback routes
tests/
└── Feature/
└── Auth/
├── AdminLoginIsEntraOnlyTest.php
├── EntraCallbackUpsertByTidOidTest.php
├── PostLoginRoutingByMembershipTest.php
├── OidcFailureRedirectsSafelyTest.php
├── SessionSeparationSmokeTest.php
└── DisabledUserLoginIsBlockedTest.php
Structure Decision: The project is a standard Laravel web application. The changes will be implemented within the existing structure, primarily affecting app/, routes/, config/ and tests/.
Complexity Tracking
No violations.