Skip to content

Fix scoped JWTs#679

Open
Rajat-Ahuja1997 wants to merge 1 commit into
mainfrom
rajat/fix-auth
Open

Fix scoped JWTs#679
Rajat-Ahuja1997 wants to merge 1 commit into
mainfrom
rajat/fix-auth

Conversation

@Rajat-Ahuja1997
Copy link
Copy Markdown
Collaborator

@Rajat-Ahuja1997 Rajat-Ahuja1997 commented May 13, 2026

Peer- and session-scoped JWTs were effectively workspace-scoped: auth…() walked the route's declared scope and fell through to a workspace match, so a {w: ws-a, p: alice} token could act on any peer in ws-a.

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced JWT scope validation to require workspace claim for peer and session-scoped tokens
    • Strengthened webhook authentication to validate workspace context explicitly
    • Refined authorization logic to enforce the token's narrowest scope for precise access control
  • Tests

    • Added comprehensive JWT authorization scope tests

Review Change Stack

…() walked the route's declared scope and fell through to a workspace match, so a {w: ws-a, p: alice} token could act on any peer in ws-a.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

Walkthrough

This PR rewrites JWT authorization logic to enforce token-scope-driven access control: verify_jwt now validates that peer/session-scoped tokens include workspace claims, auth matches token scope in priority order against route parameters, webhook endpoints explicitly declare workspace scope, and a comprehensive test suite validates the new scope contract across all scenarios.

Changes

JWT Authorization Scope Enforcement

Layer / File(s) Summary
Core JWT scope validation and authorization logic
src/security.py
verify_jwt enforces workspace claim presence for peer/session scopes; auth function rewrites to authorize by token scope priority (session → peer → workspace) with exact claim matching against route parameters and early return for self-authorizing routes.
Webhook endpoint authorization binding
src/routers/webhooks.py
Four webhook endpoints (get_or_create_webhook_endpoint, list_webhook_endpoints, delete_webhook_endpoint, test_emit) now declare explicit workspace-scope authorization via require_auth(workspace_name="workspace_id") dependency.
Comprehensive JWT scope authorization test suite
tests/test_security.py
New module with autouse fixture enabling auth, bearer helper, and five test classes validating JWT shape contract (workspace required for peer/session), peer-scoped token matching, session-scoped token matching, workspace-scoped token matching, and admin/unscoped escape-hatch behavior.
Existing scoped-API route test updates
tests/routes/test_scoped_api.py
Four test functions updated to include workspace claim (w) alongside peer (p) and session (s) claims in JWT payloads, reflecting new token shape requirement.
Test infrastructure blocklist update
tests/conftest.py
Adds test_security.py to runtime-mock blocklist so JWT scope tests run in isolation without database or runtime setup.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A workspace-scoped auth so tight,
No token can slip left or right,
Peer, session, or domain,
Must match with precision, not plain,
Security now shines oh so bright!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix scoped JWTs' directly describes the main objective of the PR: fixing the behavior of peer- and session-scoped JWTs that were incorrectly being elevated to workspace scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rajat/fix-auth

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/routers/webhooks.py (1)

40-41: 💤 Low value

Optional: Defensive workspace checks are now redundant.

The workspace validation on these lines is now performed by the auth() function in src/security.py (lines 199-200, 206-207, 214-215). These checks could be removed since auth() already enforces workspace scope matching.

However, keeping them provides defense-in-depth and has no functional impact.

Also applies to: 64-65, 82-83, 96-97

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routers/webhooks.py` around lines 40 - 41, Remove the redundant workspace
validation checks that duplicate auth()'s scope enforcement: locate the exact
conditional "if not jwt_params.ad and jwt_params.w is not None and jwt_params.w
!= workspace_id: raise AuthenticationException('Unauthorized access to
resource')" in src/routers/webhooks.py (there are four occurrences) and delete
those lines; rely on the existing auth() implementation in src/security.py to
enforce workspace matching, or if you prefer defense-in-depth, wrap them with a
clear comment referencing auth() to justify retention.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/routers/webhooks.py`:
- Around line 40-41: Remove the redundant workspace validation checks that
duplicate auth()'s scope enforcement: locate the exact conditional "if not
jwt_params.ad and jwt_params.w is not None and jwt_params.w != workspace_id:
raise AuthenticationException('Unauthorized access to resource')" in
src/routers/webhooks.py (there are four occurrences) and delete those lines;
rely on the existing auth() implementation in src/security.py to enforce
workspace matching, or if you prefer defense-in-depth, wrap them with a clear
comment referencing auth() to justify retention.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cdb29c86-f115-4044-adaa-9cd388d5a267

📥 Commits

Reviewing files that changed from the base of the PR and between a420264 and 5b3f0c3.

📒 Files selected for processing (5)
  • src/routers/webhooks.py
  • src/security.py
  • tests/conftest.py
  • tests/routes/test_scoped_api.py
  • tests/test_security.py

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