Skip to content

Conversation

tsdk02
Copy link
Contributor

@tsdk02 tsdk02 commented Jul 9, 2025

Type of Change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring
  • Dependency updates
  • Documentation
  • CI/CD

Description

This PR fixes an issue where a stale role_id from the cached lineage_context was being used to generate the JWT token during sign-in, even if the actual user role was modified (e.g., role deleted and recreated with a different role_id but same lineage).

Previously, we only validated if a user role existed for the lineage (user_id, tenant_id, org_id, merchant_id, profile_id), but did not verify that the role_id matched the current assigned role. This led to JWTs being issued with outdated role_id values.

Changes Made

  • During sign-in, added a strict match check for role_id in the fetched user role.
  • If the role_id from cached lineage_context does not match the current role fetched from DB (v2 fallback to v1), we now resolve the lineage afresh from the current user_role object.
  • Logged errors for failed role fetch attempts for better traceability.

Additional Changes

  • This PR modifies the API contract
  • This PR modifies the database schema
  • This PR modifies application configuration/environment variables

Motivation and Context

In systems where roles can be modified dynamically (e.g., deleted and recreated), relying on cached lineage_context.role_id without validating it introduces a silent inconsistency. This can lead to:

  • Unexpected authorization behavior
  • Hard-to-debug permission issues
  • Stale tokens being issued

This fix ensures that JWTs are always generated using valid and current role_id information associated with the user role.

How did you test it?

Scenario: Validate fallback when role_id has changed

  1. Initial Setup

    • Log in as an org_admin of Org A.
    • Invite User X to Org A with the role org_admin.
    • Ensure User X is also part of another organization (Org B) and has a valid user role there.
  2. Initial Sign-In

    • Sign in as User X to Org A, selecting a specific merchant and profile.
    • This populates and stores the lineage_context based on the selected values.
  3. Modify Role Assignment

    • Log back in as the original org_admin of Org A.
    • Delete the current user role (org_admin) of User X in Org A.
    • Create a new role in Org A named profile_admin using the same merchant and profile from the stored lineage_context.
    • Re-invite User X to Org A with this new profile_admin role.
  4. Re-Sign-In Validation

    • Now sign in again as User X.
    • Since the original role (org_admin) no longer exists, the cached lineage context will fail validation.
    • The system should fall back to the default sign-in flow and pick a valid user role for JWT construction.
  5. Verify Correct Role Assignment

    • If sign-in occurs into a different organization, it's acceptable.
    • If signed into Org A, validate the role_id:
      • Check the response from /user API.
      • OR decode the JWT token.
    • The role_id should now correctly reflect profile_admin.

Checklist

  • I formatted the code cargo +nightly fmt --all
  • I addressed lints thrown by cargo clippy
  • I reviewed the submitted code
  • I added unit tests for my changes where possible

@tsdk02 tsdk02 self-assigned this Jul 9, 2025
@tsdk02 tsdk02 requested a review from a team as a code owner July 9, 2025 15:17
@tsdk02 tsdk02 added the C-bug Category: Bug label Jul 9, 2025
Copy link

semanticdiff-com bot commented Jul 9, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  crates/router/src/types/domain/user/decision_manager.rs  25% smaller

.inspect_err(|e| {
logger::error!("Failed to validate V2 role: {e:?}");
})
.ok()
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this is needed.

Comment on lines +164 to +165
.map(|role| role.role_id == ctx.role_id)
.unwrap_or_default();
Copy link
Contributor

Choose a reason for hiding this comment

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

@likhinbopanna likhinbopanna added this pull request to the merge queue Jul 14, 2025
Merged via the queue into main with commit aaa4fca Jul 14, 2025
16 of 20 checks passed
@likhinbopanna likhinbopanna deleted the fix-lineage-context branch July 14, 2025 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: Bug
Projects
None yet
4 participants