Skip to content

Document request.authorized and request.peerCertificate - #735

Draft
kriszyp wants to merge 7 commits into
mainfrom
docs/request-authorized-peercert
Draft

kriszyp wants to merge 7 commits into
mainfrom
docs/request-authorized-peercert

Conversation

@kriszyp

@kriszyp kriszyp commented Oct 18, 2026 •

Copy link
Copy Markdown
Member
Mailroom worker pinning two certificates to a red-string corkboard.

⊙ Problem

The HTTP Request reference mentioned request.authorized only in prose and never mentioned request.peerCertificate. A handler doing mTLS could not tell what either returns, or that results differ behind Harper Fabric's proxy and on Bun and uWebSockets.

🤔 Is this requirement warranted?

As specified, yes. Both getters ship in Request.ts, and the proxy path from harper#1858 (v5.2.0) changes who verifies the client and what the certificate object holds. Without the rows, a reader can assume the wrong trust root. No in-flight PR covers this.

💡 Solution

  • The Request properties table gains authorized and peerCertificate, with their results on direct TLS, behind the Fabric proxy, on a plain connection, and on Bun and uWebSockets.
  • The rows show where the TLS paths differ (trusted CAs, certificate fields) and that issuerCertificate can be missing.
  • The mTLS paragraph links both rows and says authorized ignores revocation, which Harper's mTLS authentication checks separately.
  • The mTLS setup and http.mtls pages now name authority certificate records as a CA source.

🤔 Is request.authorized the right gate to recommend?

The proxy path verifies against Symphony's CA, not Harper's, so the same true can rest on different trust roots. The alternative is to point apps at Harper's mTLS authentication (request.user), which also applies revocation. I kept authorized because it works in any middleware, and added the caveats. Reversing it later means re-teaching readers.

🤔 Keep both TLS paths inside the table cells?

The peerCertificate cell is now long, and a short "Client certificates" subsection the table links to would scan better. I kept the cells so each row stands alone. Links from the mTLS paragraph land at the table top, not on the row, because no table in reference/ uses per-row anchors. Easy to restructure later.

✅ Verification

  • npm run build passes with no broken links or anchors, and npm run format:check is clean. Prettier re-widened the table, so every row in it shows as changed.
  • Checked every runtime claim against harper origin/main: the Node, Bun and uWebSockets getters in server/serverHelpers/Request.ts, and the proxy path in server/serverHelpers/proxyProtocol.ts (applyProxyHeader, synthesizePeerCertificate). The revocation caveat matches the gate in security/auth.ts.
  • git tag --contains places the proxy path (harper#1858) in v5.2.0, which the v5.2.0 badges on the new rows reflect. The related harper#1985 added connectionInfo.

🤖 Generated by Anthropic Claude Sonnet 5.5; posted via @kriszyp.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UrvaPnSVqfCTL7KPatikPN

Related PRs: none found
Complexity: medium

Deferred findings

  • 839360062b78ca53 nit documentation — reference/http/api.md — #properties links land at table top, not the new rows — NOT FILED

Review-Coverage: authored=claude; ran=gemini,cursor-muse,codex; adjudicated=domain; blocked=muse(failed); declined=cursor-grok,cursor-composer,cursor-kimi; rounds=7; full=1 @ d8b1e49

Review-Attention: skim ~2m (decisions: mirror-semantics-in-table-cells, authorized-as-recommended-gate) @ d8b1e49

kriszyp and others added 6 commits October 18, 2026 10:10
Both properties existed on the Request class (Node/Bun/uWS) but only
`authorized` was mentioned, and only in prose. Add both to the Properties
table with per-runtime behavior, and cross-link them from the "Trust and
mTLS" paragraph, which already explained authorized but not by name in a
linkable spot.

Verified against harper's server/serverHelpers/Request.ts and
proxyProtocol.ts: both getters are populated not just on a directly-
terminated TLS connection but also on Harper Fabric's proxy-protocol UDS
mirror once it decodes a verified client cert. peerCertificate returns an
empty object (not null) when the connection is TLS-capable but no client
cert was presented -- Node's own getPeerCertificate() semantics.

Dispatch-Task: documentation-request-authorized-peercert
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HbtUN4YmHf5NBj25wZZnsV
Pre-push review (codex + Harper domain) flagged that the initial wording
implied a single "server's configured CA(s)" and an identical parsed
certificate object across both paths. In fact the Fabric UDS mirror
verifies against Symphony's own client_ca_pem (symphony src/tls.rs),
not Harper's http.mtls config, and its synthesized peerCertificate
(proxyProtocol.ts synthesizePeerCertificate) carries a reduced field set
and returns {} in more cases than "no cert presented" (proxy-verified but
oversized chain omitted, or an unparseable leaf). Also drop the "added in
v5.2.0" implication -- both getters predate v5.2.0 (present in the local
v5.0.0 core tag); what's new in v5.2.0 is the Fabric mirror populating
them, so the badges are now type="changed".

Dispatch-Task: documentation-request-authorized-peercert
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HbtUN4YmHf5NBj25wZZnsV
Round-2 review (codex + gemini + domain) caught that http.mtls has no CA
field -- Harper's client CA is tls.certificateAuthority
(reference/http/configuration.md:200). Also softened "different CA" to
"not guaranteed to share a trust root": Symphony's CA and Harper's are
independently configured, not proven to always differ. Fixed a
self-contradicting "forwarded but omitted" phrase, added the omitted
`raw` field to the mirror's certificate shape (it's the escape hatch for
pubkey/bits/etc via re-parsing), scoped chain-omission language to the
mirror path only, and noted the rare authorized:true + peerCertificate:{}
combination when the forwarded leaf fails to parse.

Dispatch-Task: documentation-request-authorized-peercert
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HbtUN4YmHf5NBj25wZZnsV
…ate cases

Round-3 review (codex + gemini + domain) caught two more accuracy gaps,
both already documented elsewhere in this repo:

- Direct-TLS `authorized`/`peerCertificate` verification isn't limited to
  `tls.certificateAuthority` -- Harper also trusts any certificate record
  marked as an authority, including its own auto-generated install-time
  CA (harper core security/keys.ts). Reused this repo's existing wording
  from reference/security/certificate-verification.md:229 and linked it.
- `peerCertificate.issuerCertificate` isn't always present on a direct
  connection either: Harper omits the chain on every resumed TLS session
  and on Node.js 26.8.0/26.8.1 (documented at
  reference/security/certificate-verification.md:227).

Dispatch-Task: documentation-request-authorized-peercert
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HbtUN4YmHf5NBj25wZZnsV
…ecords on the mTLS page

- request.peerCertificate: issuerCertificate is also absent when the issuer is in
  neither the client's chain nor Harper's trusted CAs (e.g. an unverified client
  when mTLS is optional), not only on resumed sessions and Node.js 26.8.0/26.8.1.
- request.authorized reflects chain trust only; revocation is checked separately
  by Harper's mTLS authentication when http.mtls is configured.
- mtls-authentication.md named only tls.certificateAuthority as a CA source;
  certificate records marked as an authority count too.

Dispatch-Task: documentation-request-authorized-peercert
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UrvaPnSVqfCTL7KPatikPN
The http.mtls option said client certificates verify only against
tls.certificateAuthority; certificate records marked as an authority count too,
matching the mTLS authentication and request.authorized docs.

Dispatch-Task: documentation-request-authorized-peercert
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UrvaPnSVqfCTL7KPatikPN

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request updates the documentation for Harper's HTTP API, configuration, and mTLS authentication, specifically detailing the new authorized and peerCertificate request properties and clarifying CA verification behavior. The review feedback recommends enhancing the clarity and conciseness of the security warnings in the mTLS section by removing filler phrases like 'Note that' and splitting complex sentences into distinct, readable points.

Comment thread reference/http/api.md Outdated
@github-actions
github-actions Bot temporarily deployed to pr-735 October 18, 2026 16:32 Inactive
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-735

This preview will update automatically when you push new commits.

…n sentences

Drops "Note that" and gives each caveat in the Trust and mTLS paragraph its own
sentence so it can be found when scanning.

Dispatch-Task: documentation-request-authorized-peercert
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UrvaPnSVqfCTL7KPatikPN
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-735

This preview will update automatically when you push new commits.

This branch was successfully deployed

1 active deployment
pr-735 — d8b1e492 Deployed Oct 18, 2026 by github-actions[bot]
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.

1 participant