The fingerprint wizard's staff-lookup and fingerprint-save proxies forwarded the page's OTP with the session phone. a2loft resolves that phone against the domain being addressed, so an operator who holds only capture_biometric was rejected unless they were a domain super-user. The cropper already saves with the session token. - tools/server.js: both a2loft proxies send Authorization: Bearer <session token>, no phone/otp; validateProxy drops the OTP and phone checks. - tools/public/assets/fp: both OTP fields, otpLookup/otpSave state, request params and resets removed; canLookup/canSave no longer gate on OTP. - Tests assert the Bearer header, no query auth, no OTP field in the served page, and both gates without a credential (66/66 pass). - README and Help page updated. Requires the a2loft fingerprint-token-auth change deployed first. OpenSpec change: fingerprint-token-auth.
2.0 KiB
Design
Context
See proposal.md for motivation. The wizard already holds the PocketBase token
in the page (window.__SESSION__.token) for fpagent enrollment, and the
cropper's save already sends Authorization: Bearer ${req.session.token} to
a2loft through its own proxy (tools/cropper.js). The two remaining OTP calls
are the wizard's staff-lookup and fingerprint-save proxies in tools/server.js;
their handlers receive the a2loft URL from a2loftUrl/a2loftSaveUrl, which
currently append phone+otp, and validateProxy rejects a missing otp.
Goals / Non-Goals
Goals: both wizard a2loft calls use the session token; no OTP in the wizard; proxy validation keeps rejecting unauthenticated calls; deployable after the a2loft change with a clean rollback.
Non-Goals: fpagent capture (already carries the token); the cropper; a2loft's own OTP compatibility; the legacy singular fingerprint endpoint.
Decisions
- Bearer from the server session, never the browser: the proxy attaches
Authorization: Bearer ${req.session.token}, mirroringtools/cropper.js. The page's token copy stays for fpagent only. - Drop the OTP check in
validateProxy, along with the now-unnecessary phone check; keep the hardcoded-domain and reference checks.requireApialready guarantees a session. - Remove the OTP inputs and state rather than hiding them;
canLookup/canSaveno longer require an OTP.
Risks / Trade-offs
- [a2loft not yet dual-mode] → deploy the a2loft change first; this proxy change depends on it.
- [Operators outside a domain's uploader list can now enroll] → intended;
a2loft authorizes
capture_biometricwith thedomain:ididfallback. - [Rollback] → revert the proxy and re-add the OTP fields; a2loft stays dual-mode.
Migration Plan
Deploy a2loft dual-mode → deploy this app → field pass: look up a reference and save both fingerprints with no OTP; a bogus-token call fails cleanly.
Open Questions
None.