fix: Prefer header JWT when RBAC role-sync enabled#1705
Conversation
When RBAC/JWT-role sync is enabled, read the end-user JWT from the gateway-forwarded header named by get_jwt_auth_header() instead of the ibm-openrag-session cookie; preserve the existing cookie flow when RBAC is off. Strip a leading "Bearer " prefix if present and fall back to the cookie when role-sync is disabled. Added jwt_roles_enabled and get_jwt_auth_header imports and adjusted token selection logic in src/dependencies.py. Added unit tests (tests/unit/dependencies/test_ibm_header_auth.py) that cover RBAC-on header usage, RBAC-off cookie usage, and missing-header authentication failure.
WalkthroughThis pull request modifies IBM AMS authentication to switch JWT token sourcing based on RBAC enforcement: reading from a gateway-forwarded header when RBAC is enabled, and from a session cookie when disabled. The implementation includes updated logic, imports, and documentation, along with three unit tests covering both enabled/disabled paths and the missing-header error case. ChangesJWT Token Source Conditional Logic
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
Pull request overview
This PR updates IBM AMS authentication so RBAC/JWT-role sync uses the gateway-forwarded JWT header as the identity/role source, while preserving the existing cookie-based flow when RBAC is disabled.
Changes:
- Adds RBAC-aware JWT source selection in
_get_ibm_user. - Documents the header-vs-cookie behavior in the IBM auth helper.
- Adds unit coverage for RBAC-on header use, RBAC-off cookie use, and missing-header failure.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/dependencies.py |
Switches IBM JWT token selection to the configured forwarded header when JWT roles are enabled. |
tests/unit/dependencies/test_ibm_header_auth.py |
Adds unit tests for the new IBM JWT header selection behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if jwt_roles_enabled(): | ||
| raw_jwt = request.headers.get(get_jwt_auth_header(), "") | ||
| ibm_token = ( | ||
| raw_jwt[7:].strip() if raw_jwt.startswith("Bearer ") else raw_jwt.strip() | ||
| ) or None |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
tests/unit/dependencies/test_ibm_header_auth.py (1)
53-99: ⚡ Quick winSolid coverage; consider adding the role-enforcement negative case.
The three tests correctly exercise RBAC-on header sourcing, RBAC-off cookie sourcing, and the missing-header 401. The
test_rbac_on_missing_header_401case reaches 401 via the "no token at all" fall-through (Line 610-611), not via_stage_jwt_roles. Consider adding a test for RBAC-on with a header JWT present but carrying no recognized OpenRAG role, which should hit the dedicated 401 at Line 420-423 — that is the security-relevant enforcement branch. A raw (non-Bearer) header token would also round out the prefix-stripping logic.
🤖 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.
Inline comments:
In `@src/dependencies.py`:
- Around line 479-488: The code in _get_ibm_user currently reads the
gateway-forwarded JWT (via jwt_roles_enabled() and get_jwt_auth_header()) and
decodes it with decode_ibm_jwt (no signature verification), which allows forged
role claims; change _get_ibm_user to call verify_jwt_from_issuer (the same
verifier used in get_api_key_user_async) on the incoming token and use the
verified payload for _stage_jwt_roles; if verification fails, treat the token as
invalid (log/error and do not trust role claims or fall back to cookie flow).
Reference _get_ibm_user, jwt_roles_enabled, get_jwt_auth_header,
verify_jwt_from_issuer, decode_ibm_jwt, and _stage_jwt_roles when making this
change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e9acd0f0-3347-436e-9684-d59fac85f6af
📒 Files selected for processing (2)
src/dependencies.pytests/unit/dependencies/test_ibm_header_auth.py
| # When RBAC/JWT-role sync is on, the gateway forwards the end-user JWT in the | ||
| # configured header; use it as the source of identity and roles. When RBAC is | ||
| # off, preserve the existing ibm-openrag-session cookie flow. | ||
| if jwt_roles_enabled(): | ||
| raw_jwt = request.headers.get(get_jwt_auth_header(), "") | ||
| ibm_token = ( | ||
| raw_jwt[7:].strip() if raw_jwt.startswith("Bearer ") else raw_jwt.strip() | ||
| ) or None | ||
| else: | ||
| ibm_token = request.cookies.get(IBM_SESSION_COOKIE_NAME) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# (a) Confirm decode_ibm_jwt does NOT verify the signature
rg -nP --type=py -C6 'def decode_ibm_jwt\s*\('
# (b) Show the verified header path used by the /v1 surface
rg -nP --type=py -C6 'def verify_jwt_from_issuer\s*\('
# (c) Look for any middleware/config that strips or overwrites the inbound JWT/Authorization header
rg -nP --type=py -C3 'OPENRAG_JWT_AUTH_HEADER|get_jwt_auth_header|del\s+\w*headers|pop\(\s*["'\'']Authorization'Repository: langflow-ai/openrag
Length of output: 9226
RBAC header JWT is decoded without signature verification in _get_ibm_user—role claims rely on trust boundary
src/dependencies.py::_get_ibm_userreads the gateway-forwarded JWT fromrequest.headers.get(get_jwt_auth_header())(defaultAuthorization) whenjwt_roles_enabled()is on, then derives roles from it viasrc/auth/ibm_auth.decode_ibm_jwt+_stage_jwt_roles.src/auth/ibm_auth.py::decode_ibm_jwtdecodes withverify_signaturedisabled (no signature verification), so forged claims are possible unless the gateway guarantees it overwrites/strips that inbound header.- The
/v1forwarded-JWT path is already verified (get_api_key_user_async→verify_jwt_from_issuer)—so this risk is specific to theget_current_user/_get_ibm_userrole-sync flow.
Switch _get_ibm_user to verify_jwt_from_issuer (or enforce/assume a hard trust boundary where the gateway overwrites the configured JWT header) before extracting roles from the token.
🤖 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/dependencies.py` around lines 479 - 488, The code in _get_ibm_user
currently reads the gateway-forwarded JWT (via jwt_roles_enabled() and
get_jwt_auth_header()) and decodes it with decode_ibm_jwt (no signature
verification), which allows forged role claims; change _get_ibm_user to call
verify_jwt_from_issuer (the same verifier used in get_api_key_user_async) on the
incoming token and use the verified payload for _stage_jwt_roles; if
verification fails, treat the token as invalid (log/error and do not trust role
claims or fall back to cookie flow). Reference _get_ibm_user, jwt_roles_enabled,
get_jwt_auth_header, verify_jwt_from_issuer, decode_ibm_jwt, and
_stage_jwt_roles when making this change.
When RBAC/JWT-role sync is enabled, read the end-user JWT from the gateway-forwarded header named by get_jwt_auth_header() instead of the ibm-openrag-session cookie; preserve the existing cookie flow when RBAC is off. Strip a leading "Bearer " prefix if present and fall back to the cookie when role-sync is disabled. Added jwt_roles_enabled and get_jwt_auth_header imports and adjusted token selection logic in src/dependencies.py. Added unit tests (tests/unit/dependencies/test_ibm_header_auth.py) that cover RBAC-on header usage, RBAC-off cookie usage, and missing-header authentication failure.
Summary by CodeRabbit
Release Notes
New Features
Tests