Skip to content

feat(auth): add scoped application and webhook signing for Durable Streams - #5878

Draft
NathanFlurry wants to merge 1 commit into
mainfrom
stack/feat-auth-add-scoped-jwks-signing-wqyqvztn
Draft

NathanFlurry wants to merge 1 commit into
mainfrom
stack/feat-auth-add-scoped-jwks-signing-wqyqvztn

Conversation

@NathanFlurry

@NathanFlurry NathanFlurry commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Summary

Add namespace-scoped application JWTs and Engine-owned webhook signing for Durable Streams: native JWKS discovery, webhook key rings, exact-byte signatures, and guarded public and peer routes. This is the lower revision for RivetKit streams #5877 and replaces the Durable Streams signing prerequisite formerly proposed in engine-ee.

The old private ACL routes, external JWKS issuer example, and signing quotas were not ported.

Validation

  • Rust CI Check and Rustfmt pass.
  • JWT service tests: 61 passed; public and peer API tests pass.
  • A checksum-verified Engine built from this stack passed secured Durable Streams signing, JWKS rotation, webhook, and actor wake integration tests.

@railway-app

railway-app Bot commented Oct 14, 2026

Copy link
Copy Markdown

🚅 Deployed to the rivet-pr-5878 environment in rivet-frontend

8 services not affected by this PR
  • ladle
  • mcp-hub
  • frontend-cloud
  • sentry-tunnel
  • website
  • frontend-cloud-ee
  • frontend-inspector
  • kitchen-sink

@NathanFlurry

NathanFlurry commented Oct 14, 2026 •

Copy link
Copy Markdown
Member Author

Stack for rivet-dev/rivet

Get stack: forklift get 5878
Push local edits: forklift submit
Merge when ready: forklift merge 5878

change wqyqvztn

@claude

claude Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Review: scoped application and webhook signing (#5878)

I read the core pieces in depth: auth-jwt/src/webhook.rs, api-public/src/auth/webhook_keys.rs and strict_json.rs. I skimmed the rest and did not build or run any tests, so this is a static read.

What looks good

  • The design is careful. Internal key IDs stay separate from the public ds_ thumbprint IDs. The ring has a size bound on decode and validate() runs on both encode and decode. Emergency revoke is idempotent via the request ID receipt, and it compares the original arguments before resolving kids that the first commit already removed.
  • Persistence uses vbare (auth.webhook_key_ring.v1.bare, auth.grants.v2.bare), as CLAUDE.md requires. The grants change is a new versioned schema, not an in-place edit.
  • strict_json rejects duplicate members and returns a generic error that doesn't echo the input. Signature's Debug impl omits the signature bytes. Responses go through no_store.
  • The new RivetError artifacts and error-registry.json entries are included.

Issues and suggestions

  1. Duplicated reconcile logic (webhook.rs:194-282). reconcile_topology and reconcile repeat the same reconcile_issuer and recover_leader match. Share a helper so the two can't drift apart.
  2. Repeated lookups in revoke (webhook.rs:333-342). self.public_records(now) is rebuilt for every requested kid. Compute it once before the loop.
  3. Signing lease is only a doc comment (webhook.rs:387-388). sign trusts the caller's now, and the doc says callers enforce the lease. Please confirm every call site uses Engine time, and add a test for it.
  4. Layout nits (webhook.rs). #[cfg(test)] mod tests sits mid-file, before MAX_PAYLOAD_BYTES and sign. Move it to the end. A short note on why PLANNER_ISSUER (an https://rivet.dev/... URL) can't collide with a real JWT issuer would also help.
  5. Possibly unrelated changes. rivetkit-core (actor/context.rs, metrics.rs, sleep.rs, state.rs) and envoy-client/src/actor/http.rs are touched, and Cargo.lock has about 90 lines of churn. If they aren't needed for this feature, split them out. Also check that the lockfile churn isn't an accidental dependency bump.
  6. Empty PR description. CLAUDE.md asks for a short bullet list of what changed. This PR adds public endpoints, rotation and revocation semantics, and a grant schema bump, so a summary would help reviewers.
  7. Routing exposure. Please double-check that the guard/routing/api_public.rs change does not expose the peer-only /auth/webhooks/* endpoints publicly. webhook_keys::get forwards to the leader DC through those paths.
  8. Test coverage. Unit tests exist for the ring, JWKS, application tokens, recovery and JSON strictness. I saw no endpoint-level tests for ensure, rotate, revoke or the cross-DC mutate path. I also saw no test for revoke with a reused request ID and changed arguments through the API, or for the Ring::decode oversize and namespace-mismatch rejections.

Minor

  • strict_json::Unique doesn't implement visit_i128/visit_u128. That is harmless with default serde_json features, but it fails closed if arbitrary_precision is ever enabled.
  • Confirm the new workflows (webhook_recovery, webhook_rotation) emit no metrics from the #[workflow] body.

Overall this is a solid and security-conscious change. I'd address items 1, 3, 5 and 6 before merging, and add endpoint-level tests for the mutation paths.

@NathanFlurry
NathanFlurry force-pushed the stack/feat-auth-add-scoped-jwks-signing-wqyqvztn branch 3 times, most recently from 6bd9b37 to 6dcbb71 Compare October 14, 2026 09:32

This branch has not been deployed

No deployments
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.

1 participant