Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

25 KiB

Scratchpad — MSP Tenant-First SSO Provider Resolution

  • Plan slug: 2026-02-23-msp-tenant-first-sso-provider-resolution
  • Created: 2026-02-23

What This Is

Working notes for MSP SSO tenant-first resolver and provider-settings changes (Microsoft + Google), with CE enablement and no user-enumeration leakage.

Decisions

  • (2026-02-23) Scope includes both Microsoft and Google for MSP SSO tenant-first resolution; client portal remains out of scope.
  • (2026-02-23) Resolver behavior: tenant config first, app fallback second, generic failure when no source exists.
  • (2026-02-23) Unknown-user attempts must not produce externally distinguishable behavior from known-user-missing-provider cases.
  • (2026-02-23) Microsoft provider credentials will be managed in Providers settings, not per-provider email/calendar forms.
  • (2026-02-23) CE MSP SSO will be enabled through shared auth codepath changes instead of EE-only UI gating.
  • (2026-02-23) Resolver context will use short-lived signed cookie metadata (no raw secrets) to drive per-request secret selection.
  • (2026-02-23) Keep implementation core-focused: no dedicated metrics/dashboard/rollout framework changes in this phase.
  • (2026-02-23) Added a dedicated MicrosoftIntegrationSettings Providers card now, with action wiring deferred to F002-F011 to keep each checklist item atomic.

Discoveries / Constraints

  • (2026-02-23) Providers setup currently shows only Google (packages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.tsx).
  • (2026-02-23) CE MSP SSO entry is a null stub (packages/auth/src/components/SsoProviderButtons.tsx), while EE maps to ee/server/src/components/auth/SsoProviderButtons.tsx via server/next.config.mjs.
  • (2026-02-23) NextAuth provider registration in shared auth options is currently EE-gated (packages/auth/src/lib/nextAuthOptions.ts) and uses app OAuth keys.
  • (2026-02-23) NextAuth options are cached (cachedOptions), which conflicts with per-request credential-source selection.
  • (2026-02-23) Secret provider interface supports tenant writes but not app writes (packages/core/src/lib/secrets/ISecretProvider.ts), so Providers UI cannot write app-wide OAuth keys.
  • (2026-02-23) Microsoft integration flows already use tenant secret keys (microsoft_client_id, microsoft_client_secret, microsoft_tenant_id) in several existing routes/actions.
  • (2026-02-23) Google provider settings already persist tenant google_client_id/google_client_secret and can be reused as tenant SSO source for Google.
  • (2026-02-23) Existing calendar OAuth state store (packages/integrations/src/utils/calendar/oauthStateStore.ts) demonstrates Redis + memory fallback pattern for short-lived one-time state.
  • (2026-02-23) Providers tab currently renders one "Google" integration entry that can host both provider cards in a single container (IntegrationsSettingsPage.tsx).

Progress Log

  • (2026-02-23) F001 complete: added Microsoft provider card component at packages/integrations/src/components/settings/integrations/MicrosoftIntegrationSettings.tsx and rendered it in Providers tab beneath Google settings.
  • (2026-02-23) T001 complete: added IntegrationsSettingsPage.providers.test.ts to assert Providers composition includes both GoogleIntegrationSettings and MicrosoftIntegrationSettings.
  • (2026-02-23) F002 complete: added getMicrosoftIntegrationStatus action in packages/integrations/src/actions/integrations/microsoftActions.ts with masked secret output, derived Microsoft redirect URIs (email, calendar, sso), and scope metadata.
  • (2026-02-23) F003 complete: added saveMicrosoftIntegrationSettings action with validation for required client ID/client secret and optional tenant ID normalization (common default).
  • (2026-02-23) F004 complete: added resetMicrosoftProvidersToDisconnected action that disconnects Microsoft email/calendar providers and clears Microsoft token + webhook state across microsoft_email_provider_config and microsoft_calendar_provider_config.
  • (2026-02-23) F005 complete: exported Microsoft integrations actions from both packages/integrations/src/actions/integrations/index.ts and packages/integrations/src/actions/index.ts.
  • (2026-02-23) F006 complete: saveMicrosoftIntegrationSettings persists microsoft_client_id using secretProvider.setTenantSecret(tenant, 'microsoft_client_id', clientId).
  • (2026-02-23) F007 complete: saveMicrosoftIntegrationSettings persists microsoft_client_secret as tenant secret.
  • (2026-02-23) F008 complete: saveMicrosoftIntegrationSettings persists microsoft_tenant_id with default common when input is blank.
  • (2026-02-23) F009 complete: Microsoft provider settings UI now loads status and displays masked secret indicator (Stored secret: ••••) via status.config.clientSecretMasked.
  • (2026-02-23) F010 complete: saveMicrosoftIntegrationSettings and resetMicrosoftProvidersToDisconnected now enforce RBAC via hasPermission(user, 'system_settings', 'update').
  • (2026-02-23) F011 complete: status/save/reset Microsoft actions consistently reject client-portal user context with Forbidden.
  • (2026-02-23) F012 complete: added getMicrosoftProviderReadiness(tenant) helper in packages/integrations/src/actions/integrations/providerReadiness.ts requiring both microsoft_client_id and microsoft_client_secret.
  • (2026-02-23) F013 complete: added getGoogleProviderReadiness(tenant) helper that checks only google_client_id + google_client_secret (no Gmail Pub/Sub dependency).
  • (2026-02-23) F014 complete: removed manual clientId/clientSecret requirements and fields from MicrosoftProviderForm schema/UI; OAuth configuration now relies on Providers-managed credentials.
  • (2026-02-23) F015 complete: Microsoft email form now shows a "Configure Providers first" CTA (configure-microsoft-providers-link) when Microsoft provider readiness is false.
  • (2026-02-23) F016 complete: Microsoft calendar form now checks provider readiness, shows a Providers-first CTA when missing, and disables OAuth connect until provider settings are ready.
  • (2026-02-23) F017 complete: persistMicrosoftConfig now resolves Microsoft credentials from tenant provider secrets before per-provider payload values, so CE email provider persistence does not require form-entered client credentials.
  • (2026-02-23) F018 complete: Microsoft calendar form persists provider metadata without client credential inputs by creating/updating providers with provider-settings-first OAuth flow.
  • (2026-02-23) F019 complete: replaced CE SsoProviderButtons null stub with a real Google/Microsoft MSP SSO button component in packages/auth/src/components/SsoProviderButtons.tsx.
  • (2026-02-23) F020 complete: MSP SSO buttons are disabled until a non-empty email is entered (hasEmail gate in SsoProviderButtons).
  • (2026-02-23) F021 complete: Microsoft SSO button now calls POST /api/auth/msp/sso/resolve with { provider: 'azure-ad', email, callbackUrl } before invoking signIn('azure-ad').
  • (2026-02-23) F022 complete: Google SSO button now follows the same resolver-first flow (provider: 'google') before signIn('google').
  • (2026-02-23) F023 complete: MSP login SSO UI now always shows the same generic start-failure message and does not surface resolver-specific error text.
  • (2026-02-23) F024 complete: client portal login remains unchanged; ClientLoginForm still keeps SSO section commented out.
  • (2026-02-23) F025 complete: added unauthenticated resolver route server/src/app/api/auth/msp/sso/resolve/route.ts and shared resolver utilities in packages/auth/src/lib/sso/mspSsoResolution.ts.
  • (2026-02-23) F026 complete: resolver validates provider/email/callbackUrl, normalizes email casing/whitespace, and returns only generic failure responses for malformed input.
  • (2026-02-23) F027 complete: resolver performs internal-user lookup on normalized email (LOWER(email)) strictly for source-selection decisions.
  • (2026-02-23) F028 complete: resolver selects tenant source when an internal user exists and tenant credentials for the chosen provider are ready.
  • (2026-02-23) F029 complete: resolver falls back to app OAuth credentials when tenant source is unavailable and provider fallback keys are configured.
  • (2026-02-23) F030 complete: unknown-user attempts follow the same external success/failure behavior as known-user-without-tenant-config paths.
  • (2026-02-23) F031 complete: resolver returns stable 200 + { ok: true|false } schema regardless of lookup outcome, with generic failure payload shape.
  • (2026-02-23) F032 complete: resolver issues signed, short-lived, httpOnly msp_sso_resolution cookie containing only source metadata.
  • (2026-02-23) F033 complete: resolver cookie payload intentionally omits raw OAuth client IDs and client secrets.
  • (2026-02-23) F034 complete: Microsoft fallback readiness in resolver uses MICROSOFT_OAUTH_CLIENT_ID + MICROSOFT_OAUTH_CLIENT_SECRET (env/app secrets).
  • (2026-02-23) F035 complete: Google fallback readiness in resolver uses GOOGLE_OAUTH_CLIENT_ID + GOOGLE_OAUTH_CLIENT_SECRET (env/app secrets).
  • (2026-02-23) F036 complete: resolver returns the generic ok:false failure payload when no tenant or app credential source is available.
  • (2026-02-23) F037 complete: resolver now applies in-memory rate limiting keyed by request IP + hashed normalized email bucket.
  • (2026-02-23) F038 complete: resolver logs now include only provider/source classification and generic failure context without raw email, secrets, or explicit existence flags.
  • (2026-02-23) F039 complete: removed EE-only gating around Google/Microsoft provider registration in NextAuth options so CE can register MSP OAuth providers when credentials exist.
  • (2026-02-23) F040 complete: removed static cachedOptions; getAuthOptions() now rebuilds per request so resolver cookie context can affect provider credentials.
  • (2026-02-23) F041 complete: OAuth secret resolution now reads msp_sso_resolution cookie context and applies tenant-scoped Google/Microsoft credentials when valid tenant source is requested.
  • (2026-02-23) F042 complete: when resolver cookie context is missing/invalid/expired, OAuth secret resolution keeps using app-level fallback credentials only.
  • (2026-02-23) F043 complete: tenant-source cookie context is accepted only after HMAC signature and expiry checks in parseAndVerifyMspSsoResolutionCookie.
  • (2026-02-23) F044 complete: resolver writes a freshly signed cookie (new nonce + expiry) on each successful start attempt, replacing stale context.
  • (2026-02-23) F045 complete: added CE-safe OAuth mapper mapCeOAuthProfileToExtendedUser for Google/Microsoft MSP sign-in lookups by normalized internal email.
  • (2026-02-23) F046 complete: Google/Microsoft profile callbacks now route through mapOAuthProfileToExtendedUser, which selects CE mapper in community edition.
  • (2026-02-23) F047 complete: enterprise builds still follow the existing SSO registry mapper path (isEnterprise branch) unchanged.
  • (2026-02-23) F048 complete: CE now bypasses EE account-link persistence by short-circuiting ensureOAuthAccountLink when isEnterprise is false.
  • (2026-02-23) F049 complete: Microsoft provider issuer now uses ${tenantId || 'common'} to ensure empty tenant IDs default to common.
  • (2026-02-23) F050 complete: added explicit anti-enumeration comments in resolver route to prevent exposing lookup outcomes in client-visible responses.
  • (2026-02-23) F051 complete: .env.example now documents GOOGLE_OAUTH_*/MICROSOFT_OAUTH_* as CE MSP SSO fallback keys (not EE-only).
  • (2026-02-23) F052 complete: added docs/integrations/provider-setup-order.md documenting Providers-first setup, then integration-level OAuth connection for Google/Microsoft.

Commands / Runbooks

  • (2026-02-23) List existing plans and artifacts:
    • find ee/docs/plans -maxdepth 2 -type f \( -name PRD.md -o -name features.json -o -name tests.json -o -name SCRATCHPAD.md \) | head -n 40
  • (2026-02-23) Scaffold this plan folder from ALGA templates:
    • python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/scaffold_plan.py "MSP Tenant-First SSO Provider Resolution" --slug 2026-02-23-msp-tenant-first-sso-provider-resolution --no-date-prefix
  • (2026-02-23) Validate plan artifact structure:
    • python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/validate_plan.py --plan-dir ee/docs/plans/2026-02-23-msp-tenant-first-sso-provider-resolution
  • Existing Google provider settings PRD template pattern:
    • ee/docs/plans/2026-01-04-tenant-owned-google-oauth/PRD.md
  • Shared auth options and provider gating:
    • packages/auth/src/lib/nextAuthOptions.ts
  • CE/EE SSO button entry aliasing:
    • server/next.config.mjs
    • packages/auth/src/components/SsoProviderButtons.tsx
    • ee/server/src/components/auth/SsoProviderButtons.tsx
  • Providers settings page:
    • packages/integrations/src/components/settings/integrations/IntegrationsSettingsPage.tsx
  • Microsoft email/calendar forms (CE):
    • packages/integrations/src/components/email/MicrosoftProviderForm.tsx
    • packages/integrations/src/components/calendar/MicrosoftCalendarProviderForm.tsx
  • Secret provider interface:
    • packages/core/src/lib/secrets/ISecretProvider.ts

Open Questions

  • None blocking for initial implementation phase.
  • (2026-02-23) T002 complete: added unit coverage in microsoftActions.test.ts proving getMicrosoftIntegrationStatus returns success:true for authorized internal admin context.
  • (2026-02-23) T003 complete: microsoftActions.test.ts asserts Microsoft status returns masked secret indicators and never returns raw client secret text.
  • (2026-02-23) T004 complete: unit coverage verifies saveMicrosoftIntegrationSettings rejects blank clientId.
  • (2026-02-23) T005 complete: unit coverage verifies saveMicrosoftIntegrationSettings rejects blank clientSecret.
  • (2026-02-23) T006 complete: save action test verifies default microsoft_tenant_id of common when tenant ID input is omitted.
  • (2026-02-23) T007 complete: save action test verifies persistence of tenant secret key microsoft_client_id.
  • (2026-02-23) T008 complete: save action test verifies persistence of tenant secret key microsoft_client_secret.
  • (2026-02-23) T009 complete: save action test verifies persistence of tenant secret key microsoft_tenant_id.
  • (2026-02-23) T010 complete: status action test validates derived redirect URIs and scope metadata for Microsoft email/calendar/SSO.
  • (2026-02-23) T011 complete: reset action test verifies Microsoft email provider rows are set disconnected and token/webhook fields are cleared.
  • (2026-02-23) T012 complete: reset action test verifies Microsoft calendar provider rows are set disconnected and token/subscription fields are cleared.
  • (2026-02-23) T013 complete: export coverage verifies Microsoft integration actions are present in integrations index entrypoints.
  • (2026-02-23) T014 complete: save action test verifies non-admin users without system_settings:update receive Forbidden.
  • (2026-02-23) T015 complete: status/save/reset action tests verify client-portal user context is denied with Forbidden.
  • (2026-02-23) T016/T017/T023 implemented in providerReadiness.test.ts; readiness now validated as secret-pair checks (microsoft_client_*, google_client_*) with explicit assertion that Google readiness does not depend on Gmail Pub/Sub keys.
  • (2026-02-23) Command run: cd server && npx vitest run ../packages/integrations/src/actions/integrations/microsoftActions.test.ts ../packages/integrations/src/actions/integrations/providerReadiness.test.ts.
  • (2026-02-23) T017 complete: providerReadiness.test.ts verifies Google readiness is true only when both google_client_id and google_client_secret are configured.
  • (2026-02-23) T023 complete: Google readiness coverage explicitly asserts Pub/Sub keys are not required for MSP SSO readiness decisions.
  • (2026-02-23) T018 complete: microsoftProviders.providersFirst.test.ts verifies CE Microsoft email form no longer requires manual clientId/clientSecret fields and uses providers-managed credentials.
  • (2026-02-23) T019 complete: providers-first contract test verifies Microsoft email form renders CTA (configure-microsoft-providers-link) to Providers settings when readiness is false.
  • (2026-02-23) T020 complete: providers-first contract test verifies Microsoft calendar form renders CTA (configure-microsoft-calendar-providers-link) when provider readiness is missing.
  • (2026-02-23) T021 complete: calendar providers-first contract test verifies create flow submits metadata and uses empty vendor credential fields (no manual OAuth credential entry requirement).
  • (2026-02-23) T022 complete: persistence contract test verifies Microsoft email provider action derives effective credentials from hosted/tenant secrets and does not rely on form-entered secrets.
  • (2026-02-23) T024 complete: added SsoProviderButtons.msp.test.tsx to validate CE MSP login renders both Google and Microsoft SSO buttons.
  • (2026-02-23) Command run: cd server && npx vitest run --coverage.enabled=false ../packages/auth/src/components/SsoProviderButtons.msp.test.tsx ../packages/auth/src/components/ClientLoginForm.ssoGuard.test.ts.
  • (2026-02-23) T025 complete: SSO button interaction tests verify both providers stay disabled until a non-empty email is supplied.
  • (2026-02-23) T026 complete: component test verifies Microsoft button performs resolver POST first and only then invokes signIn('azure-ad').
  • (2026-02-23) T027 complete: component test verifies Google button performs resolver POST first and then calls signIn('google').
  • (2026-02-23) T028 complete: failure-path component test verifies resolver/network failures always emit one generic MSP SSO start error message.
  • (2026-02-23) T029 complete: client portal login contract test verifies ClientLoginForm keeps SSO section commented/disabled with no new client portal SSO affordance.
  • (2026-02-23) T030 complete: added resolver route unit coverage validating valid payload -> { ok: true } and signed msp_sso_resolution cookie set on success.
  • (2026-02-23) Added auth/server test suites: packages/auth/src/lib/sso/mspSsoResolution.test.ts and server/src/app/api/auth/msp/sso/resolve/route.test.ts.
  • (2026-02-23) Added Vitest alias for @alga-psa/auth/lib/sso/mspSsoResolution in server/vitest.config.ts to enable route test resolution.
  • (2026-02-23) Command run: cd server && npx vitest run --coverage.enabled=false ../packages/auth/src/lib/sso/mspSsoResolution.test.ts src/app/api/auth/msp/sso/resolve/route.test.ts.
  • (2026-02-23) T031 complete: resolver route test verifies invalid provider input returns the generic { ok:false, message } response contract.
  • (2026-02-23) T032 complete: mspSsoResolution.test.ts verifies resolver lowercases/trims email before DB lookup binding.
  • (2026-02-23) T033 complete: helper test verifies Microsoft tenant source selection when user exists and tenant Microsoft secrets are ready.
  • (2026-02-23) T034 complete: helper test verifies Google tenant source selection when user exists and tenant Google secrets are ready.
  • (2026-02-23) T035 complete: helper test verifies Microsoft app fallback source when tenant Microsoft secrets are unavailable.
  • (2026-02-23) T036 complete: helper test verifies Google app fallback source when tenant Google secrets are unavailable.
  • (2026-02-23) T037 complete: route test verifies unknown-user and known-user-missing-tenant both produce identical success schema with app fallback.
  • (2026-02-23) T038 complete: route test verifies unknown-user and known-user-no-source both return identical generic failure payload.
  • (2026-02-23) T039 complete: signed-cookie helper test verifies payload/value exclude raw OAuth client IDs and secrets.
  • (2026-02-23) T040 complete: signed-cookie helper test validates provider/source/issuedAt/expiresAt/nonce fields plus parseable signature.
  • (2026-02-23) T041 complete: helper test asserts Microsoft app fallback checks use MICROSOFT_OAUTH_CLIENT_ID and MICROSOFT_OAUTH_CLIENT_SECRET.
  • (2026-02-23) T042 complete: helper test asserts Google app fallback checks use GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET.
  • (2026-02-23) T043 complete: helper test verifies invalid signature and expired cookie contexts are rejected by resolver-cookie parser.
  • (2026-02-23) T044 complete: route test verifies rate-limited requests still return the same generic failure response.
  • (2026-02-23) T045 complete: route test verifies logs include provider/source classification without raw email, secret material, or user-existence fields.
  • (2026-02-23) T046 complete: added nextAuthOptions.mspContract.test.ts asserting CE path registers Google/Microsoft providers when credential inputs are available.
  • (2026-02-23) Added auth/doc test suites: ceOAuthProfileMapper.test.ts, nextAuthOptions.mspContract.test.ts, and mspSsoDocsContract.test.ts.
  • (2026-02-23) Command run: cd server && npx vitest run --coverage.enabled=false ../packages/auth/src/lib/sso/ceOAuthProfileMapper.test.ts ../packages/auth/src/lib/nextAuthOptions.mspContract.test.ts ../packages/auth/src/lib/sso/mspSsoDocsContract.test.ts.
  • (2026-02-23) T047 complete: NextAuth contract test verifies getAuthOptions returns buildAuthOptions() directly and no static cachedOptions cache remains.
  • (2026-02-23) T048 complete: NextAuth contract test verifies tenant-scoped Microsoft credentials are read when resolver cookie selects tenant source.
  • (2026-02-23) T049 complete: NextAuth contract test verifies tenant-scoped Google credentials are read when resolver cookie selects tenant source.
  • (2026-02-23) T050 complete: NextAuth contract test verifies invalid/absent resolver context returns early to app-level fallback credential set.
  • (2026-02-23) T051 complete: NextAuth contract test verifies expired resolver context is ignored through the same early-return fallback path.
  • (2026-02-23) T052 complete: resolver route test verifies consecutive successful starts set different cookie values (overwrite behavior).
  • (2026-02-23) T053 complete: CE mapper unit test verifies normalized-email resolution for Microsoft profile and expected extended user shape.
  • (2026-02-23) T054 complete: CE mapper unit test verifies normalized-email resolution for Google profile and expected extended user shape.
  • (2026-02-23) T055 complete: CE mapper unit test verifies inactive accounts are rejected for MSP OAuth sign-in.
  • (2026-02-23) T056 complete: CE mapper unit test verifies non-internal/client user types are rejected for MSP OAuth sign-in.
  • (2026-02-23) T057 complete: NextAuth contract test verifies enterprise path still delegates profile mapping to EE SSO registry implementation.
  • (2026-02-23) T058 complete: NextAuth contract test verifies ensureOAuthAccountLink short-circuits when isEnterprise is false.
  • (2026-02-23) T059 complete: NextAuth contract test verifies Microsoft issuer uses tenant ID with common default in dynamic and sync provider configuration.
  • (2026-02-23) T060 complete: docs contract test verifies explicit anti-enumeration guidance comments remain in resolver route implementation.
  • (2026-02-23) T061 complete: docs contract test verifies .env.example includes CE MSP SSO fallback usage for GOOGLE_OAUTH_* and MICROSOFT_OAUTH_*.
  • (2026-02-23) T062 complete: docs contract test verifies provider setup order documentation instructs Providers settings before integration OAuth connections.
  • (2026-02-23) T063 complete: resolver helper integration-style test covers tenant-source selection when a matching internal user row and tenant provider secrets are present.
  • (2026-02-23) T064 complete: resolver route test covers unknown-email guard path returning generic response without user-existence disclosure.
  • (2026-02-23) T065 complete: resolver helper integration-style test covers app-source selection when user row exists but tenant provider readiness is absent.
  • (2026-02-23) T066 complete: expanded SsoProviderButtons.msp.test.tsx with end-to-end contract scenario for Microsoft tenant-source success from login button click through NextAuth signIn invocation.
  • (2026-02-23) Updated auth flow contract tests: SsoProviderButtons.msp.test.tsx, ClientLoginForm.ssoGuard.test.ts, and MspCredentialsFlow.contract.test.ts.
  • (2026-02-23) Command run: cd server && npx vitest run --coverage.enabled=false ../packages/auth/src/components/SsoProviderButtons.msp.test.tsx ../packages/auth/src/components/ClientLoginForm.ssoGuard.test.ts ../packages/auth/src/components/MspCredentialsFlow.contract.test.ts.
  • (2026-02-23) T067 complete: SSO component end-to-end contract scenario verifies Google tenant-source success path reaches NextAuth signIn.
  • (2026-02-23) T068 complete: SSO component end-to-end contract scenario verifies Microsoft app-fallback success path reaches NextAuth signIn.
  • (2026-02-23) T069 complete: SSO component end-to-end contract scenario verifies Google app-fallback success path reaches NextAuth signIn.
  • (2026-02-23) T070 complete: end-to-end contract scenario verifies unknown-user and known-unconfigured tenant failures surface the identical generic UI message.
  • (2026-02-23) T071 complete: credentials-flow contract test verifies MSP credentials sign-in path remains separate from resolver-cookie handling.
  • (2026-02-23) T072 complete: client portal login contract test verifies SSO affordances remain disabled/commented for end-to-end client portal flow.