@afauthhq/worker
v0.1.1
Published
AFAuth Cloudflare Workers bindings — createWorker, DurableObjectNonceStore, KvNonceStore, D1AccountStore
Downloads
360
Readme
@afauthhq/worker
Cloudflare Workers bindings for the AFAuth Protocol. Wraps
@afauthhq/server in a Worker-native router and provides storage
implementations backed by Durable Objects, KV, and D1.
Quickstart
import {
AFAuthNonceDO,
createNonceDurableObject,
createWorker,
DurableObjectNonceStore,
KvRevocationList,
} from "@afauthhq/worker";
import {
consoleEmailHandler,
MemoryAccountStore,
type DiscoveryDocument,
} from "@afauthhq/server";
// Re-export the nonce DO base class under whatever class_name your
// wrangler.toml binding declares (default: `AFAuthNonceDO`).
export class AFAuthNonceDO extends createNonceDurableObject() {}
interface Env {
AFAUTH_NONCE_DO: DurableObjectNamespace;
AFAUTH_REVOCATIONS: KVNamespace;
}
const discovery: DiscoveryDocument = { /* ... */ };
const accounts = new MemoryAccountStore(); // replace with durable impl
export default {
fetch(req, env: Env, ctx) {
const handler = createWorker({
nonceStore: new DurableObjectNonceStore(env.AFAUTH_NONCE_DO),
revocationList: new KvRevocationList(env.AFAUTH_REVOCATIONS),
serviceDid: discovery.service_did,
accounts,
recipients: { email: consoleEmailHandler },
discovery,
baseUrl: "https://api.example.com",
extractOwnerSession: async (req) => /* your session extraction */ null,
});
return handler.fetch!(req, env, ctx);
},
};wrangler.toml binding for the DO:
[[durable_objects.bindings]]
name = "AFAUTH_NONCE_DO"
class_name = "AFAuthNonceDO"
[[migrations]]
tag = "v1"
new_classes = ["AFAuthNonceDO"]Nonce store: pick DO, not KV
§5.6 requires the seen-nonce set be shared and atomic across
verifier instances. Cloudflare KV is shared but offers no atomic
check-and-set: a get-then-put window admits cross-isolate
replay during the freshness window.
| Store | Atomic? | Shared? | When to use |
|---|---|---|---|
| DurableObjectNonceStore | yes | yes | recommended for production |
| KvNonceStore | no | yes | dev only, or single-region low-value deployments where the trade-off is documented |
| MemoryNonceStore (from @afauthhq/server) | yes | no | tests only |
DurableObjectNonceStore partitions by keyid so unrelated agents
fan out across distinct actor instances; only requests from the same
agent share an actor and serialize against each other.
Exports
createWorker(opts)— returns anExportedHandlerrouting the five AFAuth endpoints to@afauthhq/serverhandlers. Routing is done with a small in-house router (ADR-0002).createNonceDurableObject()— factory that returns a Durable-Object base class implementing the §5.6 atomic check-and-set protocol. Subclass it in your Worker module and register the subclass inwrangler.toml.DurableObjectNonceStore—NonceStorethat delegates to the DO above. Spec-compliant atomic insert; recommended for production.KvNonceStore—NonceStorebacked by Cloudflare KV. Has a known eventual-consistency replay window; see the JSDoc on the class. Suitable for dev/low-value deployments only.KvRevocationList—RevocationListbacked by Cloudflare KV (§8.3). Durable; no TTL.KvRateLimiter—RateLimiterbacked by Cloudflare KV (§11.3). Fixed-window counter per key; eventually-consistent reads mean racing isolates may over-count (fail-safe per §11.3), never under-count.D1AccountStore—AccountStorebacked by Cloudflare D1 (§6 + §7.3). Every ADR-0004 named atomic op usesD1.batch()for transactional grouping. The schema lives atmigrations/0001_init.sql; apply viawrangler d1 migrations apply <db-name>before first use. Schema is portable to standard Postgres/MySQL with minor syntactic changes.WorkerOptions— extendsServerOptionswith the requiredextractOwnerSessioncallback for the claim-completion route.
See also
AFAuthHQ/spec— protocol spec.@afauthhq/server— the handlerscreateWorkerdispatches to.examples/worker/— runnable reference Worker that prefers DO when its binding is configured and falls back to KV (with a warning) otherwise.
