Skip to content

refactor: share auth-plugin construction and wire the Worker's KV stores - #20

Merged
zippy merged 6 commits into
mainfrom
feat/worker-kv-parity
Aug 21, 2026
Merged

zippy merged 6 commits into
mainfrom
feat/worker-kv-parity

Conversation

@zippy

@zippy zippy commented Aug 18, 2026

Copy link
Copy Markdown
Member

Split out of the multi-network PR: this is the Cloudflare Worker half, which touches no joining logic and reviews on its own.

The Worker entry point had drifted from the Node one. buildAuthPlugins and flattenMethods lived inside src/server.ts, so deploy/cloudflare/worker-entry.ts carried a hand-copied version of the same switch — one that had silently dropped agent_allow_list and delegated_verification entirely (hit in production by the unyt fork). Both entry points now call one shared src/auth-plugins.ts, with deps passed as an options object rather than four positional arguments.

That extraction is the prerequisite for the rest: the Worker's local copy had nowhere to accept a store, so it could not wire one. It now constructs all three against the SESSIONS binding — KvAllowedAgentStore, KvNetworkStore, and LinkerRegistrationStore — gated on exactly the same config as the Node entry point. Every dynamic-registration admin surface works on Workers with no manual wiring. The linker store also feeds KvUrlProvider, so dynamically registered linkers merge into URL provisioning alongside the static ones.

  • A compile-time exhaustiveness guard replaces the drift. Every concrete AuthMethod gets its own case, so TypeScript narrows the default branch to exactly the custom x-${string} member. Adding a method to the union in src/types.ts without a case for it now fails to compile — this is the class of bug that let the Worker skip whole auth methods unnoticed.
  • Docs updated: DEPLOYMENT.md and JOINING_SERVICE_API.md no longer claim dynamic registration needs manual worker wiring or is Node-only.

Breaking / operational notes:

  • The Worker now throws on misconfigurations it previously ignored silently — e.g. delegated_verification listed in auth_methods without its config block, or email_code without a transport. Previously the Worker's local switch had no case for these and skipped them; a deployment that was quietly running without an auth method it thought was enabled will now fail to start. This is the intended behavior (it matches Node), but check Worker configs before deploying.
  • Dynamic linker registration on Node remains library-embedding-only. LinkerRegistrationStore is built against a KV-namespace-shaped store and no Node (sqlite/memory) implementation of that shape ships. Running it on Node means importing createApp and supplying your own linkerRegistrationStore. Documented, not fixed here.

Stacks on the multi-network PR — merge that first.


Commits (2)

Commit Concern
refactor: share auth-plugin construction and wire the Worker's KV stores src/auth-plugins.ts, both entry points, three KV stores
docs: dynamic registration on Workers and Node

Diff vs the multi-network tip: 7 files, +270/-184.

zippy added 4 commits August 17, 2026 16:03
buildAuthPlugins and flattenMethods lived inside server.ts, so the Cloudflare
worker entry carried its own divergent copy of the same switch -- one that had
no `agent_allow_list` or `delegated_verification` cases at all, and picked up
new auth methods only when someone remembered to update both. Extracted to
src/auth-plugins.ts and taken by both entry points, with the deps passed as an
options object rather than four positional arguments.

That extraction is what lets the worker entry wire its stores, since the old
local copy had nowhere to accept them. It now constructs all three against the
SESSIONS binding -- KvAllowedAgentStore, KvNetworkStore, and
LinkerRegistrationStore -- gated on the same config as the Node entry point, so
the allowed-agent, network, and linker admin routes work on Workers with no
manual wiring. The linker store also feeds KvUrlProvider, merging dynamically
registered linkers into URL provisioning alongside the static ones.

Note that deploy/ is outside tsconfig's `include` and no test covers
worker-entry.ts, so this file is checked by neither `npm run typecheck` nor
`npm test`; the release workflow bundles it with esbuild, which does not
typecheck.
The docs still said dynamic registration of allowed agents and networks
needed manual worker wiring and was Node-only out of the box; that stopped
being true once the bundled worker entry started constructing the KV-backed
stores itself.

Also records the gap that remains: Node has no KV-shaped store for dynamic
*linker* registration, so running that on Node means embedding the service
as a library and supplying a linkerRegistrationStore.
Adds a "Client Integration" section covering the decision a client makes
on startup -- which endpoint to call given whether an agent key exists and
whether the hApp is installed -- why reconnect goes first (both orders are
safe, so it is about what each request needs from the caller: reconnect a key
and a signature, join possibly claims and a user prompt), and the requirement
to record the agent-key-to-hApp association locally before calling /v1/join.
The Overview's flow summary gains the matching recovery stanza.

It lands as section 4, so the sections after it are renumbered: Error Response
Format 4->5, CORS and Rate Limiting 5->6, Security Considerations 6->7,
Authentication Methods Reference 7->8, Example Flows 8->9 (and its 8.x
subsections to 9.x), TypeScript Type Definitions 9->10. Two cross-references
name a moved section and are updated: auth methods in the /v1/info field table,
and the src/types.ts header comment pointing at the type definitions.
References to 3.x subsections are unaffected.

Also adds example flow 9.10, recovery after an interrupted install, and
corrects flow 9.5's reconnect response, which named a `linker_urls_expire_at`
field the service does not return -- expiry is per linker_urls entry.
Security Considerations now states what the service does and does not do:
admission control, not fork prevention. A key holder can copy the conductor
directory and fork without ever calling the service; that is Holochain's
problem, handled by validation and warrants. Records why the 409 stays as it
is -- /v1/join has no proof of key possession, so an idempotent join would
turn a public agent key into a provisioning credential and skip auth
evaluation.

Adds the reconnect replay window: the signed payload is the timestamp alone
within a configurable tolerance (default 300s) and ready sessions do not
expire, so an observed request replayed inside the window returns the session
token. Notes the available mitigations and that signing over the agent key
plus a nonce is the durable fix.

Also corrects the session-expiry bullet, which claimed 1 hour pending / 24
hours ready; the stores never expire ready sessions and pending sessions use
session.pending_ttl_seconds (default 24 hours).
@zippy
zippy requested review from ThetaSinner and zo-el August 18, 2026 14:41
Covers JoiningClient: constructing one, choosing a network, driving the
join/verify/provision flow, and the crash-recovery path via reconnect.

Both construction paths get their own example rather than one worked
example plus a prose aside, since which one applies is decided by whether
the app domain publishes a well-known document, not by preference -- and
the choice determines whether join() can route to a network on its own.
The three forms of join()'s network argument are likewise shown as three
calls instead of described as one three-way parameter.

Provision handling branches on what is present instead of assuming a
shape. Every field is optional and which ones arrive is a property of the
deployment: a membrane-proof-only or gateway-only service returns no
linker_urls at all, and /v1/info omits linker_info to match, so an absent
linker is the normal case for those deployments rather than an error.
docs: client integration guide, admission-control scope, and README client library
Base automatically changed from feat/multi-network to main August 21, 2026 15:24
@zippy
zippy merged commit 2f95bbc into main Aug 21, 2026
1 check passed
@zippy
zippy deleted the feat/worker-kv-parity branch August 21, 2026 15:24
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