auth-service: delegate NATS user permissions to scoped signing key#437
auth-service: delegate NATS user permissions to scoped signing key#437Joey0538 wants to merge 1 commit into
Conversation
|
Warning Review limit reached
Next review available in: 53 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (8)
📝 WalkthroughWalkthroughThe auth-service JWT signer now uses account-tagged scoped claims instead of inline publish/subscribe allow lists. Tests were updated for the new claim shape, and the local setup script now provisions and exports a dedicated signing key seed for auth-service. ChangesScoped NATS auth flow
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
fd387a6 to
5605f50
Compare
The account signing key used to mint NATS user JWTs is being rotated to a
scoped signing key whose role template declares the per-user subject
grants centrally (chat.user.{{tag(account)}}.>, chat.room.>, _INBOX.>,
presence read + query). Centralizing grants on the key means changes to
the allowed subject shape flow through one key config instead of every
consumer of this signing key, and NATS enforces the scope uniformly.
signNATSJWT drops the inline Pub/Sub allow lists and instead:
- Adds an `account:<account>` tag so {{tag(account)}} in the scope
template resolves per user.
- Calls SetScoped(true) so per-user NatsLimits are cleared — a scoped SK
rejects any per-user limits on the JWT even when they'd resolve to the
same effective cap, because the scope owns limits.
Renamed AUTH_SIGNING_KEY → AUTH_SCOPED_SIGNING_KEY to make the required
value's type explicit at every callsite. The variable is not yet set in
any deployed environment (still pre-staging), so the rename is a
zero-risk clarity win.
docker-local/setup.sh mirrors the prod key layout so local dev enforces
the same isolation: the chatapp account gets a scoped signing key with
the auth-service scope template, and AUTH_SCOPED_SIGNING_KEY in the
generated .env is the scoped SK seed (not the account root seed).
Without this, local user JWTs — signed by an unscoped root key with no
inline perms — would silently receive unrestricted pub/sub, masking
scope violations that would fail in prod.
Client-facing behavior is unchanged: the effective subject grants
documented in client-api.md still apply, sourced from the scope template
instead of the JWT's inline allow lists.
5605f50 to
ddf722b
Compare
Why
The account signing key the auth service uses to mint NATS user JWTs is being rotated to an account scoped signing key. The scope's role template declares the per-user subject grants centrally on the key itself (
chat.user.{{tag(account)}}.>,chat.room.>,_INBOX.>, presence read + query), and NATS enforces those grants uniformly at connect time — regardless of what a JWT tries to assert.Motivation for the rotation:
Once the key was rotated, the auth service kept issuing JWTs (no server-side error) but frontend NATS connections failed with
Authorization Violationbecause the JWT the auth service produced isn't compatible with a scoped signing key.What changed
signNATSJWTno longer inlines Pub/Sub allow lists. Two adjustments make it compatible with the scoped signing key:account:<account>tag so{{tag(account)}}in the scope template resolves per user (e.g.chat.user.alice.>for accountalice).UserPermissionLimits.jwt.NewUserClaimspopulatesNatsLimitswith-1("unlimited") defaults. Scope enforcement rejects any non-zero per-user limit — even one that encodes the same effective cap — because the scope owns limits. Clearing the struct produces the same wire formatnscemits under a scoped signing key.Client-facing impact
None. The effective subject grants documented in
docs/client-api.mdare identical — samechat.user.{account}.>,chat.room.>,_INBOX.>, presence read/query. They're now supplied by the scope template instead of being inlined per JWT. ThePOST /authrequest and response schemas are unchanged.Backend services
backend.creds(loaded bymessage-worker,broadcast-worker,room-service, etc.) is unaffected: it's a separate long-lived credential signed by a different key path fromAUTH_SIGNING_KEY.Test plan
make lint— cleanmake test SERVICE=auth-service— all unit tests updated and passingTestHandleAuth_ValidToken— assertsTagscontainsaccount:<account>,Pub.AllowandSub.Alloware empty,UserPermissionLimitsis zeroTestHandleAuth_PermissionsPerUser— asserts per-account tag isolationTestHandleAuth_DevMode_ValidRequest— asserts tag for dev-mode pathAUTH_SIGNING_KEY; frontend connects and can publish/subscribe under its ownchat.user.{account}.>namespaceaccount(platform team)Generated by Claude Code
Summary by CodeRabbit