Summary#
- Implements
POST /v1/accounts/sessions— email + password login for the provisioning API - Adds
resolve_by_emailDB helper indb/accounts.rs(sibling toresolve_identifier) - Corrects the original MM-85 spec: device_token auth was the early design; all mobile accounts now have
password_hashset during the DID ceremony, making email + password the right mechanism
What it does#
When the app's provisioning session_token has expired or been lost (app reinstall, Keychain reset), this endpoint lets the user re-authenticate and get a fresh 1-year opaque bearer token compatible with all require_session-protected provisioning endpoints.
Request: POST /v1/accounts/sessions
{ "email": "user@example.com", "password": "..." }
Response:
{ "sessionToken": "...", "did": "did:plc:..." }
Implementation notes
Reuses verify_password, rate-limit functions (is_rate_limited / record_failure / clear_failures), and generate_token — no new auth primitives
Same 1-year TTL and token format as create_did.rs
NULL password_hash accounts (pre-DID ceremony) return 401
Test plan
Valid email + password returns 200 with sessionToken and did
sessionToken hash is queryable by the require_session DB lookup
Wrong password → 401 AUTHENTICATION_REQUIRED
Unknown email → same 401 (identical body to wrong password — no enumeration)
NULL password_hash account → 401
Deactivated account → 401
Rate limit triggers after RATE_LIMIT_MAX_FAILURES failures → 429
Successful login clears rate-limit counter