# Implementation Plan: 063 — Entra Sign-in (Tenant Panel) v1 **Branch**: `063-entra-signin` | **Date**: 2026-01-27 | **Spec**: [specs/063-entra-signin/spec.md](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 an `OperationRun`. 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) ```text specs/063-entra-signin/ ├── plan.md ├── research.md ├── data-model.md ├── quickstart.md ├── contracts/ │ └── entra-auth-flow.md └── tasks.md ``` ### Source Code (repository root) ```text # 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.