diff --git a/.gitignore b/.gitignore index 4ecedd4..54b3890 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ dist/ node_modules/ target/ +.wrangler/ bench/.trace/ diff --git a/README.md b/README.md index 6a44152..24186f6 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Use this deployment to test an implementation. | :------------------------------------------------- | :------------------------------------------- | | [Browser extension](./examples/browser-extension/) | Adds a `Signature` on every outgoing request | | [Rust](./examples/rust/) | Signs a hardcoded test request | +| [Cloudflare Workers](./examples/signing-worker/) | Forwards requests to a target, signed | ### Verifying diff --git a/examples/signing-worker/package.json b/examples/signing-worker/package.json new file mode 100644 index 0000000..e74a016 --- /dev/null +++ b/examples/signing-worker/package.json @@ -0,0 +1,11 @@ +{ + "name": "signing-worker", + "private": true, + "scripts": { + "deploy": "npx wrangler deploy", + "dev": "npx wrangler dev" + }, + "dependencies": { + "web-bot-auth": "*" + } +} diff --git a/examples/signing-worker/src/index.ts b/examples/signing-worker/src/index.ts new file mode 100644 index 0000000..24c8675 --- /dev/null +++ b/examples/signing-worker/src/index.ts @@ -0,0 +1,39 @@ +import { sign, SIGNATURE_AGENT_HEADER } from "web-bot-auth"; +import { signerFromJWK } from "web-bot-auth/crypto"; + +interface Env { + TARGET: string; + SIGNATURE_AGENT: string; + // Set with `wrangler secret put JWK`. Defaults to the published RFC 9421 test key. + JWK?: string; +} + +// Published RFC 9421 test key. Never use it in production. +const RFC_9421_ED25519_TEST_KEY = { + kty: "OKP", + crv: "Ed25519", + d: "n4Ni-HpISpVObnQMW0wOhCKROaIKqKtW_2ZYb2p9KcU", + x: "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs", +}; + +export default { + async fetch(request: Request, env: Env): Promise { + const signer = await signerFromJWK( + env.JWK ? JSON.parse(env.JWK) : RFC_9421_ED25519_TEST_KEY + ); + const outgoing = new Request(env.TARGET, request); + outgoing.headers.set( + SIGNATURE_AGENT_HEADER, + `sig1="${env.SIGNATURE_AGENT}";type=directory` + ); + const now = new Date(); + const fields = await sign(outgoing, { + signer, + created: now, + expires: new Date(now.getTime() + 300_000), + }); + outgoing.headers.set("Signature", fields.signature); + outgoing.headers.set("Signature-Input", fields.signatureInput); + return fetch(outgoing); + }, +}; diff --git a/examples/signing-worker/wrangler.jsonc b/examples/signing-worker/wrangler.jsonc new file mode 100644 index 0000000..8e8f96f --- /dev/null +++ b/examples/signing-worker/wrangler.jsonc @@ -0,0 +1,9 @@ +{ + "name": "signing-worker", + "main": "src/index.ts", + "compatibility_date": "2026-09-03", + "vars": { + "TARGET": "https://http-message-signatures-example.research.cloudflare.com/debug", + "SIGNATURE_AGENT": "https://http-message-signatures-example.research.cloudflare.com", + }, +} diff --git a/package-lock.json b/package-lock.json index 9c7668b..f6f1a4a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,11 @@ "libsodium-wrappers": "0.8.4" } }, + "examples/signing-worker": { + "dependencies": { + "web-bot-auth": "*" + } + }, "examples/verification-workers": { "version": "0.1.0", "license": "Apache-2.0", @@ -6392,6 +6397,10 @@ "dev": true, "license": "ISC" }, + "node_modules/signing-worker": { + "resolved": "examples/signing-worker", + "link": true + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",