Skip to content

Adopt the open GET /who and the verifier model for endorsements - #4

Merged
samlown merged 10 commits into
mainfrom
net-verifier
Jul 29, 2026
Merged

Adopt the open GET /who and the verifier model for endorsements#4
samlown merged 10 commits into
mainfrom
net-verifier

Conversation

@samlown

@samlown samlown commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Syncs the default-authority registry to the revised GOBL Net spec (invopop/gobl#909).

  • /who serves the static self-signed party envelope over a GET, replacing the authenticated POST exchange.
  • Request tokens (§5.5): /who and /inbox require a bearer request token, verified by a requireAuth middleware against the requester's published key, audience, and freshness window — 401 otherwise, with token_missing/token_invalid/token_expired audit reasons; authenticated requests are logged with the requester address. Key discovery and the public /parties directory stay open. /who is served with Cache-Control: private.
  • Outbound requests authenticate as the lookup itself: the sender GET /who eligibility check and countersigned-envelope deliveries carry bearer tokens. A registrant deferring its own /who disclosure (202) is rejected with 403 — senders must disclose openly to register.
  • Endorsements move from the scope claim to structural verification (spec §5.3): gobl.lookup verify <address> re-countersigns the stored envelope with a verifier claim. --verifier names an external KYC/KYB authority — whose own countersignature must already be present on the envelope — and defaults to the lookup itself, whose single countersignature carries both attestations.
  • Registration.Verifier replaces the stored scope; unchanged-party renewals preserve it, changed party data drops it. The verifier signature's exp is independent of the 90-day registration cycle, so verifications can live a year or more (EV-certificate style).
  • Fixes a latent flake: generated keys floor valid_from to the second.

Draft until the next gobl release: go.mod pins the net-request-tokens branch by pseudo-version (v0.503.1-0.20260725214141-df55536c0206), so CI resolves and runs; swap for the tagged release before merging.

🤖 Generated with Claude Code

samlown and others added 10 commits July 25, 2026 17:07
Syncs the registry to the revised GOBL Net spec:

- /who serves the lookup's static self-signed party envelope with a
  plain GET (the old authenticated POST exchange is gone).
- The scope claim is replaced by structural verification: a
  registration countersignature alone asserts a registered identity,
  and `gobl.lookup verify` marks a registration as identity-verified
  by re-countersigning with a `verifier` claim. --verifier names an
  external verifying authority (its own countersignature must
  already be on the stored envelope); the default is the lookup
  itself, whose single countersignature carries both attestations.
- Registration records store `verifier` instead of `scope`; renewals
  with an unchanged party keep it, changed party data drops it (KYC
  must be repeated). The verifier's own countersignature may be much
  longer-lived than the 90-day registration cycle.
- Generated keys floor valid_from to the second so signatures made
  within the same second verify.

Pinned to the local gobl via a replace directive until the next gobl
release; drop it before merging.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Aligns the registry with the revised protocol (spec §5.5):

- A requireAuth middleware verifies the Authorization header of every
  /who and /inbox request against the requester's published key,
  audience, and freshness window; failures get 401 with
  token_missing / token_invalid / token_expired audit reasons, and
  authenticated requests are logged with the requester address. Key
  discovery and the public /parties directory stay open.
- /who serves the static envelope with Cache-Control: private; the
  token's issuer may be a trusted intermediary — the registration
  subject still comes from the envelope's own signature.
- Outbound requests authenticate as the lookup: the sender GET /who
  eligibility check (via the client identity) and countersigned
  envelope deliveries (HTTPSender mints a token per POST) both carry
  bearer tokens. A registrant deferring its own /who disclosure
  (202) is rejected with 403 — senders must disclose openly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follows the gobl core change dropping the URI scheme from signed
iss/aud/verifier claims: countersigning and the party self-signature
use Address.String(), and the registration aud check canonicalizes
both sides with net.ParseAddress, mirroring gobl's VerifyEnvelope.
The gobl: scheme remains on org.Endpoint URIs (Identity.URI stays
for endpoint scaffolding).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The --insecure client flag no longer exists; local registration
needs a domain-shaped hostname and a TLS-terminating proxy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Absorb gobl's review fixes: transient conditions (network failures,
429, 5xx) now surface as net.ErrUnavailable, distinct from invalid
tokens and definitive rejections.

- requireAuth answers 503 (reason token_unavailable) when the
  requester's key endpoint cannot be reached, instead of 401.
- Registration answers 503 (new domain kind ErrUnavailable, reason
  who_unavailable) when the sender's /who cannot be reached during
  the eligibility check — a 403 would make the sender stop retrying
  a registration that would succeed moments later.
- Outbound deliveries return the retryable net.ErrUnavailable for
  transport failures, 429, and 5xx; ErrInboxRejected is reserved for
  definitive 4xx rejections.
- Test fetchers implement the Fetcher interface's new Post method.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Documents the target design for upgrading a registration to
verified via https://lookup.gobl.org/verify/<address>: email OTP
gate against the party's published mailbox, a trusted-verifier
picker, a background session hand-off pinning the stored envelope's
uuid+dig, the provider's own KYC/KYB process (payment included as a
fraud signal, keeping the registry free), the countersigned renewal
back through the standard inbox, auto-verify when a trusted
verifier's countersignature arrives, and delivery + self-publishing
by the subject. Ends with the implementation gap list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the local ../gobl filesystem pin with the pushed branch
commit (v0.503.1-0.20260725214141-df55536c0206) so CI can resolve
the module and run tests and the linter. Swap for the tagged
release once it ships.

Also settle a racy assertion in TestInboxAcceptsRegistration: the
async delivery goroutine is instant with the mock sender, so the
record may legitimately read countersigned or delivered.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Verification becomes list-driven: the registry accepts a configured
set of verification providers (--verifiers / VERIFIERS) and derives
the verifier claim from the countersignatures already on the
envelope instead of taking it as input.

- Auto-verify: a registration or renewal carrying a valid
  countersignature from an accepted provider is verified on
  arrival. The countersignature is cryptographically checked
  against the provider's published key before being named — a
  forged signature claiming a provider's address is ignored, and an
  unreachable key endpoint registers unverified with an
  inbox.auto_verify_unavailable log rather than rejecting.
- gobl.lookup verify <address> loses --verifier and becomes a
  recovery command: it re-runs the same derivation on the stored
  envelope, e.g. after a provider joins the accepted list. With no
  accepted countersignature it fails; with an unreachable provider
  key endpoint it returns 503-mapped ErrUnavailable.
- The verified_at timestamp follows the verifier: kept across
  renewals with the same provider, stamped fresh on a new one,
  cleared when the verifier is dropped.
- The discovery link stamped on countersigned envelopes uses the
  standard `verification` category; the previous `authority` value
  failed envelope validation as soon as the stored envelope was
  re-signed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@samlown
samlown marked this pull request as ready for review July 29, 2026 22:28
Copilot AI review requested due to automatic review settings July 29, 2026 22:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@samlown
samlown merged commit ac4a6b7 into main Jul 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants