Skip to content

Mount @dwk/solid-oidc and let /pod trust its tokens - #89

Merged
davidwkeith merged 3 commits into
mainfrom
claude/bold-babbage-oxg7t5
Oct 24, 2026
Merged

davidwkeith merged 3 commits into
mainfrom
claude/bold-babbage-oxg7t5

Conversation

@davidwkeith

@davidwkeith davidwkeith commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

dwk.io now runs its own Solid-OIDC provider (@dwk/solid-oidc 1.0.0-beta.2). It is the only catalog endpoint that wasn't deployed anywhere live.

  • Provider: discovery is at /.well-known/openid-configuration, and authorize, token and jwks live under /oidc. The issuer is https://dwk.io. Discovery, the JWKS and the token endpoint allow cross-origin requests, with a preflight on the token endpoint, so browser Solid apps can call them. The authorize endpoint is a browser navigation, so it doesn't need CORS.
  • Consent: goes through the existing Access-guarded /auth/login as a third signed flow (solid-oidc), and the page names the WebID. The package doesn't check the redirect_uri against the client-ID document yet, so the consent page, which shows the client and its redirect, is the only check.
  • WebID: /profile/card now names solid:oidcIssuer <https://dwk.io>.
  • Pod: /pod accepts DPoP-bound tokens from the provider as well as the OWNER_TOKEN bearer. It needs two handlers over the same pod, because a package authenticate hook replaces the built-in verifier entirely. The pod fetches the JWKS through siteFetch, so the request stays in-process and avoids the 522 a Worker gets when fetching its own domain.
  • New secret: OIDC_SIGNING_KEY, a P-256 private JWK. CLAUDE.md has the one-liner to generate it. Until it's set, the mount answers 503 and the rest of the site keeps serving.
  • Preview cleanup: the new .github/workflows/preview-cleanup.yml deletes a PR's Worker Preview when the PR is merged or closed. Workers Builds never deletes Previews, and each one holds five Durable Object namespaces. The free plan allows 100 per account, which is why this PR's own preview failed to deploy (code: 10067). The workflow needs a repository secret CLOUDFLARE_API_TOKEN with Workers Scripts: Edit. CLAUDE.md documents the limit.

After merging:

  1. Run wrangler secret put OIDC_SIGNING_KEY. No new bindings are needed, and the code table is created lazily in AUTH_DB.
  2. Add the CLOUDFLARE_API_TOKEN repository secret.
  3. Delete the existing stale Previews by hand, since the workflow only catches PRs that close from now on.

Tests: test/solid-oidc.test.ts covers discovery, CORS (including none on authorize), a JWKS that publishes only the public key, the redirect to the owner sign-in, the WebID issuer, and the 503 when unconfigured. It also checks that the pod accepts a write with an OP-minted DPoP token and refuses a token signed with any other key. npm run check reports no errors, and all 79 tests in npm test pass. The cleanup workflow is checked for valid YAML and shell syntax only. It first runs when this PR closes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SVMgqnS8W4euNdsZn3m7ck

dwk.io now runs its own Solid-OIDC provider: discovery at
/.well-known/openid-configuration, authorize/token/jwks under /oidc,
consent through the existing Access-guarded /auth/login (a third
signed flow). The WebID names https://dwk.io as its solid:oidcIssuer,
and /pod accepts the provider's DPoP-bound tokens alongside the
OWNER_TOKEN bearer. New secret: OIDC_SIGNING_KEY (P-256 private JWK).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVMgqnS8W4euNdsZn3m7ck
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://claude-bold-babbage-oxg7t5-dwk.8k9dgysp29.workers.dev (commit db2337f)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://ca81b080-dwk.8k9dgysp29.workers.dev db2337f 2026-10-24T19:17:26.916Z Visit the dashboard ↗
  • Build: Failed ❌

View logs ↗
922be30 2026-10-24T04:22:45.112Z View logs ↗
  • Build: Failed ❌

View logs ↗
678844c 2026-10-24T03:29:38.597Z View logs ↗

Copy link
Copy Markdown
Owner Author

Review of #89. I found nothing blocking in the diff, but the Workers Builds: dwk check is red, so look at that before merging.

Looks good

  • The /pod dispatch is sound. isOwner is the same check podAuthenticate already used. Owner bearer requests go to the owner handler and everything else goes to the OIDC handler, which verifies the issuer, JWKS and DPoP binding. A bad token gets a 401 there, and the test covers it.
  • The Solid-OIDC login flow is consistent with the others. requestFromQuery now signs the PKCE challenge for solid-oidc, matching what the approval hook sees on return. The consent page shows the WebID for this flow.
  • The OIDC_SIGNING_KEY unset case falls back to the 503 NotConfiguredError path like the other mounts, and a test covers it.
  • The OIDC_SIGNING_KEY JWK committed in vitest.config.ts is test-only. Make sure that key is never reused in production.

Things to check

  1. Workers Builds: dwk failed in 0 seconds. That points to a build or config problem rather than a code failure. Check the build log. The test job was still running when I looked.
  2. CORS on /oidc/authorize. withCors adds Access-Control-Allow-Origin: * to the authorize redirects and the login redirect too. That's harmless, since no cookies are involved, but you only need it on discovery, jwks and token.
  3. redirect_uri is only checked on the consent page. You noted this in the PR description: the package doesn't validate redirect_uri against the client document. Consent shows the redirect, so a mistaken approval is the only exposure. Consider restricting redirect_uri to the client ID's origin in approveAuthorization as a cheap extra check.
  4. Preview environments. Previews don't inherit production secrets, so /oidc will answer 503 there until OIDC_SIGNING_KEY is set with wrangler preview base-config secret put. This matches how the other mounts behave.

I haven't run the tests locally. Please confirm CI is green and the build failure is understood.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Workers Builds: dwk failed on 678844c, and I can't see why. The check posts no log output, and the full log is only in the Cloudflare dashboard, which I can't open.

Some things point to the build never starting:

  • Its details link goes to production/builds/…. Every successful preview on earlier PRs links to production/previews/<branch>/builds/… instead, so the preview for this new branch doesn't look like it was created.
  • The same commit installs and builds cleanly from scratch with the npm version I have locally (10.9.4).
  • wrangler deploy --dry-run bundles fine with every binding resolved.
  • The test job passes.

Two caveats: the preview build may run on a different npm version than mine, and wrangler preview itself, the step the preview build runs, wasn't reproduced.

I can't re-run this check from here. Could you open the log, or press Retry build there? I'll fix anything it shows that comes from this PR.


Generated by Claude Code

It is a top-level navigation, not a cross-origin fetch; discovery, JWKS,
and the token endpoint keep it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVMgqnS8W4euNdsZn3m7ck

Copy link
Copy Markdown
Owner Author

Replies to the review:

  1. Build failure: still unexplained, see my earlier comment. The new push, 922be30, starts a fresh Workers Build.
  2. CORS on /oidc/authorize: fixed in 922be30. Discovery, the JWKS and the token endpoint keep CORS, and authorize has none now. A test asserts it.
  3. Requiring redirect_uri to share the client ID's origin: left as is for now. The Solid-OIDC spec ties the redirect to the redirect_uris listed in the client ID document, not to its origin. A same-origin rule would reject legitimate apps whose client ID document is hosted somewhere else. The correct check is fetching that document, which is the package's first deferred hardening. It belongs in @dwk/solid-oidc rather than in this site. Until then, the consent page shows the full redirect_uri, and that is the check.
  4. Previews: agreed. /oidc answers 503 on a preview until npx wrangler preview base-config secret put OIDC_SIGNING_KEY is run.

Generated by Claude Code

Copy link
Copy Markdown
Owner Author

I found the cause of the Workers Builds: dwk failure from the build log: This account has reached the Workers Free limit of 100 Durable Object namespaces per account [code: 10067]. The code built and uploaded fine; the deploy step for this branch's preview is what failed.

It isn't caused by this PR, which adds no Durable Objects. Each Preview gets its own copy of the 5 Durable Object namespaces in the previews block (ACTOR, POD, STORAGE, WEBAUTHN, REPO). That means about 19 previews plus production use up all 100, and this repo has 35 branches.

To fix it, free namespaces by deleting stale previews with npx wrangler preview delete --name <preview-name>, then retry the build. Each preview is named after its branch, for example claude-gallant-dijkstra-h17qie. The other option is Workers Paid, which raises the limit to 500.


Generated by Claude Code

Each Preview carries its own copy of the Worker's five Durable Object
namespaces; the free plan's 100-namespace account limit made new
Previews fail to deploy (code 10067). Workers Builds never deletes
them, so a pull_request closed workflow does, by branch name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SVMgqnS8W4euNdsZn3m7ck
@davidwkeith
davidwkeith merged commit bc3e2fd into main Oct 24, 2026
2 checks passed
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