You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(#3003): implement DB-first intersection for session token team scoping
Implement the intersection approach for session token team resolution:
DB teams are always resolved first (revoked memberships enforced
immediately), then narrowed to the intersection with any JWT-embedded
teams claim. This delivers the #3003 user story — users can scope a
session to a subset of their memberships — without risking stale grants.
Key changes:
- resolve_session_teams() now applies intersection policy with
preresolved_db_teams support for the batched queries path
- Add resolve_session_teams_sync() for StreamableHTTP transport
- Route all 6 session-token call sites through the policy point
- Skip _check_team_membership for session tokens (DB resolution
already validates; raw JWT check conflicts with fallback semantics)
- Cache raw DB teams (not narrowed intersection) to prevent
cross-session cache poisoning
- Document intersection behavior and empty-intersection fallback
Closes#3003
Signed-off-by: Jonathan Springer <jps@s390x.com>
Copy file name to clipboardExpand all lines: docs/docs/architecture/multitenancy.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -319,7 +319,7 @@ Token scoping is the mechanism that determines which resources a user can **see*
319
319
**Key functions** in `mcpgateway/auth.py`:
320
320
321
321
-`normalize_token_teams()` — The **single source of truth** for interpreting JWT team claims into a canonical form. Used directly by API tokens and legacy tokens.
322
-
-`resolve_session_teams()` — The **single policy point** for session-token team resolution. Session tokens (`token_use: "session"`) always resolve teams from the database via `_resolve_teams_from_db()`so that revoked memberships take effect immediately.
322
+
-`resolve_session_teams()`/ `resolve_session_teams_sync()`— The **single policy point** for session-token team resolution. Teams are always resolved from the database first so that revoked memberships take effect immediately. If the JWT carries a `teams` claim, the result is narrowed to the intersection of DB teams and JWT teams — letting callers scope a session to a subset of their memberships without risking stale grants. If the intersection is empty (e.g. all JWT-claimed teams have been revoked), the full DB team list is returned as a fallback so the user is not locked out.
323
323
- API tokens and legacy tokens always use `normalize_token_teams()` directly.
Copy file name to clipboardExpand all lines: docs/docs/manage/rbac.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -138,7 +138,7 @@ Protected entities:
138
138
139
139
## Token Scoping Model
140
140
141
-
Token scoping controls what resources a token can access based on the `teams` claim in the JWT payload. The `normalize_token_teams()` function is the **single source of truth** for interpreting JWT team claims into a canonical form. For session tokens, `resolve_session_teams()` is the **single policy point** — it always resolves teams from the database so that membership changes take effect immediately.
141
+
Token scoping controls what resources a token can access based on the `teams` claim in the JWT payload. The `normalize_token_teams()` function is the **single source of truth** for interpreting JWT team claims into a canonical form. For session tokens, `resolve_session_teams()` is the **single policy point** — it resolves teams from the database first (so revoked memberships take effect immediately), then narrows the result to the intersection with any JWT-embedded `teams` claim (so callers can scope a session to a subset of their memberships). If the intersection is empty (e.g. all JWT-claimed teams have been revoked), the full DB team list is returned as a fallback.
0 commit comments