Key changes Adds Entra OIDC redirect + callback endpoints under /auth/entra/* (token exchange only there). Upserts tenant users keyed by (entra_tenant_id = tid, entra_object_id = oid); regenerates session; never stores tokens. Blocks disabled / soft-deleted users with a generic error and safe logging. Membership-based post-login routing: 0 memberships → /admin/no-access 1 membership → tenant dashboard (via Filament URL helpers) >1 memberships → /admin/choose-tenant Adds Filament pages: /admin/choose-tenant (tenant selection + redirect) /admin/no-access (tenantless-safe) Both use simple layout to avoid tenant-required UI. Guards / tests Adds DbOnlyPagesDoNotMakeHttpRequestsTest to enforce DB-only render/hydration for: /admin/login, /admin/no-access, /admin/choose-tenant with Http::preventStrayRequests() Adds session separation smoke coverage to ensure tenant session doesn’t access system and vice versa. Runs: vendor/bin/sail artisan test --compact tests/Feature/Auth Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box> Reviewed-on: #76
52 lines
2.6 KiB
Markdown
52 lines
2.6 KiB
Markdown
# Research: 063 — Entra Sign-in
|
|
|
|
## 1. Required OAuth Scopes for Entra ID Sign-in
|
|
|
|
**Decision**: Use the standard OpenID Connect scopes: `openid`, `email`, `profile`.
|
|
|
|
**Rationale**:
|
|
- `openid`: Required for OIDC compliance, returns the `sub` (subject) claim which can be used for the user identifier.
|
|
- `email`: Requests the `email` claim.
|
|
- `profile`: Requests claims like `name`, `family_name`, `given_name`.
|
|
The `tid` and `oid` claims are standard in Microsoft's implementation and do not require special scopes.
|
|
|
|
**Alternatives considered**:
|
|
- Requesting more specific scopes (e.g., `User.Read` from Microsoft Graph). This is not necessary for basic sign-in and would require the Graph API, which is out of scope for the login flow itself.
|
|
|
|
## 2. User Provisioning Strategy
|
|
|
|
**Decision**: Just-In-Time (JIT) provisioning using `updateOrCreate`.
|
|
|
|
**Rationale**:
|
|
- The `spec.md` requires upserting the user based on `(entra_tenant_id, entra_object_id)`.
|
|
- Laravel's `updateOrCreate` is the idiomatic way to handle this. It will find a user with the matching `entra_tenant_id` and `entra_object_id` or create a new one if none exists.
|
|
- The `User` model will be updated with information from the Entra ID claims (name, email).
|
|
|
|
**Alternatives considered**:
|
|
- Pre-provisioning users. This would require an admin to manually create users before they can sign in, which is not a good user experience.
|
|
|
|
## 3. Interaction with Tenant RBAC
|
|
|
|
**Decision**: The sign-in flow will only *read* tenant memberships after the user is authenticated.
|
|
|
|
**Rationale**:
|
|
- The `spec.md` is clear: "063 MUST NOT refactor tenant RBAC data model or enforcement. It may only **read** memberships to decide where to redirect after login."
|
|
- After the user is upserted and logged in, a service class will be used to check their tenant memberships (e.g., `Auth::user()->tenants()->count()`).
|
|
- The result of this check (0, 1, or N) will determine the redirect path as per the spec.
|
|
|
|
**Alternatives considered**:
|
|
- Modifying RBAC during login. This is explicitly out of scope.
|
|
|
|
## 4. User Experience for Unmapped/New Users
|
|
|
|
**Decision**: The user experience is defined by the post-login routing based on tenant memberships.
|
|
|
|
**Rationale**:
|
|
- If a new user signs in via Entra, they will be created in the `users` table.
|
|
- At this point, they will have 0 tenant memberships.
|
|
- According to the spec (`FR-003`), they will be redirected to `/admin/no-access`.
|
|
- This page will instruct them to "Ask an admin to add you." This is the desired flow.
|
|
|
|
**Alternatives considered**:
|
|
- Displaying an error on the login page. This is less user-friendly than guiding them to a page that explains the next steps.
|