{"_id":"@anyknown/oauth-relay","_rev":"2-939e4988e3027898c4c27c1c68164042","name":"@anyknown/oauth-relay","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@anyknown/oauth-relay","version":"0.1.0","license":"MIT","_id":"@anyknown/oauth-relay@0.1.0","maintainers":[{"name":"anyknown-admin","email":"admin@anyknown.com"}],"dist":{"shasum":"5b57fe180a4dc9feec993bced06093ca6d0c3781","tarball":"https://registry.npmjs.org/@anyknown/oauth-relay/-/oauth-relay-0.1.0.tgz","fileCount":23,"integrity":"sha512-+2oKc1lGuKdKLXTw26IGk/KkZbCahvgvL6IbQeC6qok8jSE5xDigi+/MYxDXsBsuQlNDTRCF0YtjK5aYhXCXag==","signatures":[{"sig":"MEUCIQCqapTetlfHc/IPEbOXASm4Al2NH0rA41c2PUWf+J1bxgIgCakjxn2EGrPzj4e3Q3bCGmVxmJPst2uM2qQEarJcIo0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":61081},"type":"module","_from":"file:anyknown-oauth-relay-0.1.0.tgz","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./contract":{"types":"./dist/contract.d.ts","default":"./dist/contract.js"}},"scripts":{"lint":"oxlint src","test":"vitest run","build":"tsc -p tsconfig.build.json","lint:fix":"oxlint --fix src","typecheck":"tsc --noEmit"},"_npmUser":{"name":"anyknown-admin","email":"admin@anyknown.com"},"_resolved":"/private/var/folders/15/xx5gnq1x6bj7gbqszhy_1m4m0000gp/T/cdd4499fcc5a56b0c25638fd4ed611ce/anyknown-oauth-relay-0.1.0.tgz","_integrity":"sha512-+2oKc1lGuKdKLXTw26IGk/KkZbCahvgvL6IbQeC6qok8jSE5xDigi+/MYxDXsBsuQlNDTRCF0YtjK5aYhXCXag==","_npmVersion":"10.9.7","description":"Optional stateless OAuth authorization-code relay for local-first clients","directories":{},"_nodeVersion":"22.22.2","dependencies":{"hono":"4.12.33"},"_hasShrinkwrap":false,"devDependencies":{"oxlint":"1.76.0","vitest":"4.1.10","typescript":"6.0.3","@types/node":"25.9.5"},"_npmOperationalInternal":{"tmp":"tmp/oauth-relay_0.1.0_1785888471041_0.3714339583420969","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@anyknown/oauth-relay","version":"0.1.2","description":"Optional stateless OAuth authorization-code relay for local-first clients","license":"MIT","repository":{"type":"git","url":"git+https://github.com/anyknown-com/anyknown.git","directory":"packages/oauth-relay"},"type":"module","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./contract":{"types":"./dist/contract.d.ts","default":"./dist/contract.js"}},"scripts":{"build":"tsc -p tsconfig.build.json","lint":"oxlint src","lint:fix":"oxlint --fix src","typecheck":"tsc --noEmit","test":"vitest run"},"dependencies":{"hono":"4.12.33"},"devDependencies":{"@types/node":"25.9.5","oxlint":"1.76.0","typescript":"6.0.3","vitest":"4.1.10"},"gitHead":"d14473f9e0c0f397e987f24dbfc7163c14e9d81c","_id":"@anyknown/oauth-relay@0.1.2","bugs":{"url":"https://github.com/anyknown-com/anyknown/issues"},"homepage":"https://github.com/anyknown-com/anyknown#readme","_nodeVersion":"22.23.1","_npmVersion":"12.0.2","dist":{"integrity":"sha512-1+LmTETSKAYEqM2vFw+ZrwBd+po8gW9d9qALu8pnx/B7yzcbWt0YFJ3SqE3k44h75WDXUPuVaQ2o/hvK8wx00g==","shasum":"495c53951321daa3794fcb845eb1cf36e4443e96","tarball":"https://registry.npmjs.org/@anyknown/oauth-relay/-/oauth-relay-0.1.2.tgz","fileCount":23,"unpackedSize":61774,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@anyknown%2foauth-relay@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICli+Vc+sHNZbadtIjxNjvq7OKSQOzC5WpNsONKuNg4lAiEApzeA6XfDuOxsBdm9ctiRO4zk/ckjI5S2DcvxwF6b+Oo="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:3b76411e-1822-4268-b034-78318b3d407f"}},"directories":{},"maintainers":[{"name":"anyknown-admin","email":"admin@anyknown.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/oauth-relay_0.1.2_1785894417247_0.11485354594645192"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-05T00:07:50.816Z","modified":"2026-08-05T01:46:57.749Z","0.1.0":"2026-08-05T00:07:51.235Z","0.1.2":"2026-08-05T01:46:57.395Z"},"license":"MIT","description":"Optional stateless OAuth authorization-code relay for local-first clients","maintainers":[{"name":"anyknown-admin","email":"admin@anyknown.com"}],"readme":"# @anyknown/oauth-relay\n\nAn open-source, auditable Hono sub-app for handing an OAuth authorization code back to a local client. It is intentionally not an identity service, deployment, token exchange service, or token vault.\n\n> **MCP hub works fully offline; the relay is optional and stateless.**\n\nAnyknown chooses a PKCE localhost loopback flow whenever a provider supports it. The relay is used only when a provider forbids localhost redirect URIs or when a shared Anyknown `client_id` requires a fixed callback. Token exchange happens directly between the CLI and the provider, and credentials stay on the user's machine.\n\n## Mount the sub-app\n\n```ts\nimport {createOAuthRelay, type HandoffStore} from \"@anyknown/oauth-relay\"\nimport {Hono} from \"hono\"\n\nconst store: HandoffStore = createHostHandoffStore()\nconst app = new Hono()\napp.route(\"/oauth\", createOAuthRelay({store}))\n\nexport default app\n```\n\nThe mounted routes are:\n\n- `GET /oauth/callback` — validates relay state and an optional return URL, then creates a short-lived authorization-code handoff.\n- `POST /oauth/redeem` — verifies the original state and PKCE verifier, atomically consumes the handoff, and returns the code once.\n\nThe built-in `InMemoryHandoffStore` is suitable for local development and single-isolate demos. It lazily removes expired records and defaults to a hard 10,000-handoff capacity, but it is not shared across isolates. Production hosts inject a `HandoffStore` implementation. Its `create` and verified `redeem` operations **must be atomic**; raw eventually-consistent KV is not enough for one-time redemption. A Cloudflare host should serialize KV access with a Durable Object or use another compare-and-delete primitive.\n\n## Handoff contract\n\nThe CLI creates an encoded `RelayStatePayload` containing:\n\n- contract version `1`\n- a random handoff ID and nonce\n- the S256 PKCE challenge\n- issue and expiry timestamps\n- an optional browser return URL\n\nThe callback stores only the provider authorization code, the state digest, the challenge, and timestamps. A handoff lives for at most 60 seconds after callback. Redeem sends the original encoded state and `code_verifier`; a matching request atomically deletes and returns the code. Wrong verifiers do not consume a valid handoff. Callback redirects never contain the provider code.\n\nThe relay never receives or stores access tokens or refresh tokens. Responses use `Cache-Control: no-store`, callback HTML has a restrictive CSP, remote return URLs require an explicit HTTPS-origin allowlist, and the default callback return policy permits only IP loopback HTTP (`127.0.0.1` or `[::1]`).\n\n## Client API\n\nThe package also exports the shared contract and client helpers:\n\n- `selectOAuthPath` — loopback by default; relay only for provider restrictions or shared clients\n- `prepareOAuthFlow` — creates state and PKCE parameters\n- `pollRelayHandoff` / `validateLoopbackCallback` — obtains the authorization code\n- `exchangeAuthorizationCode` — exchanges the code directly with the provider over HTTPS\n\nTreat a prepared flow as secret-bearing process memory. Its PKCE verifier is deliberately non-enumerable so accidental JSON serialization and journals do not include it.\n\n## Local workerd demo\n\nFrom the repository root:\n\n```bash\npnpm --filter @anyknown/oauth-relay-demo dev\n```\n\nThis starts a Vite shell on `http://127.0.0.1:4175` and a local Wrangler/workerd process on port `8788`. It is a fixture only and has no deployment command.\n\n## Host responsibilities\n\nA production host supplies atomic ephemeral storage, rate limiting, abuse controls, provider OAuth app configuration, and deployment. It should mount this package at `/oauth`, retain the 60-second maximum handoff TTL, and never log callback query strings, redeem bodies, authorization codes, PKCE verifiers, or credentials.\n","readmeFilename":"README.md","homepage":"https://github.com/anyknown-com/anyknown#readme","repository":{"type":"git","url":"git+https://github.com/anyknown-com/anyknown.git","directory":"packages/oauth-relay"},"bugs":{"url":"https://github.com/anyknown-com/anyknown/issues"}}