Pending-claim recovery¶
This repository-only MVP is non-gating for isolated synthetic rehearsal and gating before real-user migration (#2922, parent #2466). It does not authorize deployment, user communications, migration, or changes to live mappings.
Boundary¶
The canonical schema's Identity-only identityFeatureFlags group emits
SYRF__FeatureFlags__IdentityClaimRecovery from
featureFlags.identityClaimRecovery, default false. Identity binds the
FeatureFlags section once at startup into its own IdentityFeatureFlags type
(IdentityHostOptions.FeatureFlags), not the shared-kernel FeatureFlags class.
The entry carries no featureFlag: true annotation or web: block, so it is absent
from the API runtime flag catalogue and browser flags: an admin runtime toggle could
never reach Identity. Generated Helm supports Identity; the bulk chart-defaults updater
currently does not, so Identity's chart explicitly declares the same false default.
With the flag off, recovery GET/POST handlers return 404, the admission middleware
does not exempt /Account/ClaimPending (so an incomplete account is still sent to
its admission step), and authorization retains its existing unmapped-account refusal. With it on, an interactive authorization
request for an authenticated, otherwise-ready unmapped user opens
/Account/ClaimPending. Silent prompt=none, token, and userinfo refusal behavior
is unchanged. Existing password-reset, email-confirmation, and profile gates still
apply; the recovery page cannot bypass them.
The initial redirect follows the existing login/admission return-URL convention:
GET query parameters or POST form authorization parameters (including OAuth
state) appear in the local return URL. Protection of the retry continuation
starts on the recovery page, not before this redirect; this slice does not claim
to hide the original authorization request from browser history. Clients must
not place credentials or personal data in OAuth state.
User and support path¶
Pending and rejected/unmapped accounts receive identical guidance: contact the existing helpdesk with the displayed random support reference, or check again after support confirms readiness. No account/investigator identifier, email, candidate information, credential, or rejection reason appears in the page.
Each page response records an outcome and random support reference. Authorized
operators can correlate that reference in Identity logs; the account identifier
is attached only using the existing PiiUserId scope/redaction convention. This
reference is not a credential or authorization to edit a mapping. The MVP supplies
no operator mapping-edit endpoint and sends no automated helpdesk communication.
Both handlers load the account through the same security-stamp validation as
authorization: a stale cookie (for example after a password change) is signed out
and challenged before any continuation is issued. A GET for an account that is
already mapped resumes the original authorization request immediately. A
redirect to an unmet admission step also records an AdmissionRequired outcome
and support reference.
Retry is authenticated and antiforgery-protected (one token, emitted by the form
tag helper). It validates the existing 15-minute, account-and-security-stamp-bound protected local
continuation, and reads the stored SyrfUserId. An absent mapping only renews the
guidance. A present mapping resumes the original local authorization request;
only that existing authoritative flow can grant admission. Retry never links,
creates, infers, or changes any mapping, and never issues tokens or refreshes a
sign-in cookie. Expired, altered, or wrong-account continuations require starting
sign-in again. External and protocol-relative return URLs fall back to /.
Verification and follow-ups¶
Focused tests cover pending/rejected guidance, repeated read-only retries, resolved continuation, wrong account/stamp, expiry/tampering, external return URLs, other admission requirements, flag-off behavior, silent authorization, privacy-safe audit events, real Razor rendering, and HTTP antiforgery enforcement. GET and form-POST authorization tests cover enabled, disabled and silent flows; POST uses the form's state rather than a competing query-string value. The HTTP harness uses synthetic users and no live database or credentials.
Operator reconciliation tooling, detailed claim-state UX, and real-user rollout remain separate work. Do not enable this flag as a substitute for verified immutable mapping or for the other migration acceptance gates.