Files
tools-legacy/openspec/changes/cropper-token-auth/proposal.md
T
adebisi-fa 796094f61b feat(cropper): save with the session token — no OTP, domain from a2loft
Consumes the a2loft cropper-token-auth change: the save now sends the
session's PocketBase token as a bearer credential and no phone/otp. The
backend authorizes with OpenFGA crop_image (domain:<code> -> domain:idid),
so an operator no longer needs super-user rights in the profile's domain —
which is what made saves fail with a blanket 'Invalid OTP specified.'.

- the save's domain comes from a2loft's own record of the picture
  (dims/picture/{uploadId} -> domainCode), falling back to the queue label,
  guarded by a path-safety pattern instead of the catalog check
- the 'core' -> 'uc' alias is deleted: 'core' is a2loft's own pseudo-domain
  for a profile picture (special-cased there), so rewriting it changed the
  attribution and the ID-card notification
- queue loads are enriched with the profile's domainCode; the panel shows
  the profile's domain and, when it differs, the picture target
- the cropper's OTP field, state and parameters are gone; the fingerprint
  wizard is untouched (its own OTP flow on its own endpoints)
- tests updated: bearer + no query auth, resolved domain wins, unsafe values
  refused, no OTP field served (46 pass)

Requires the a2loft change deployed first.
2026-10-01 12:37:25 +01:00

1.8 KiB

Proposal: cropper-token-auth

Why

The cropper's save proves the operator with a phone number and an OTP. a2loft resolves that phone against the domain being saved to, so an operator without super-user rights in that domain is rejected with a blanket Invalid OTP specified. — even though they are authorized to crop images for the domain. The a2loft endpoints now accept a PocketBase token (see the a2loft change cropper-token-auth), which authorizes with OpenFGA crop_image and takes the actor's identity from the token.

What Changes

  • The cropper's save posts the session token to a2loft instead of phone + otp; the OTP input is removed from the UI.
  • The save's domain comes from a2loft's own picture record (dims/picture/{uploadId} → domainCode), falling back to the queue item's label, and the panel shows both (the profile's domain and the picture target).
  • The core → uc alias is deleted: core is a2loft's own pseudo-domain for a profile picture, not an alias for uc.
  • The fingerprint wizard's staff lookup and fingerprint save keep their OTP; only the cropper's calls change.

Capabilities

New Capabilities

(none)

Modified Capabilities

  • image-cropper: the save is token-authenticated (no OTP), the domain comes from a2loft's record, and the OTP requirement is removed.

Impact

  • tools/cropper.js: save handler (Bearer token, no ?otp=), domain resolution via dims with the label as fallback, path-safety check replacing the catalog check, queue loads enriched with the profile's domain.
  • tools/public/assets/cropper/: the OTP field and all otp state removed; the panel shows the profile's domain and the picture target.
  • Requires the a2loft cropper-token-auth change to be deployed first.