Skip to content

Conversation

@drtechie
Copy link
Member

@drtechie drtechie commented May 30, 2025

πŸ“‹ Description

JIRA ID: AMM-1507

Check if jti is present in deny list before authenticating.

βœ… Type of Change

  • 🐞 Bug fix (non-breaking change which resolves an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • πŸ”₯ Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • πŸ›  Refactor (change that is neither a fix nor a new feature)
  • βš™οΈ Config change (configuration file or build script updates)
  • πŸ“š Documentation (updates to docs or readme)
  • πŸ§ͺ Tests (adding new or updating existing tests)
  • 🎨 UI/UX (changes that affect the user interface)
  • πŸš€ Performance (improves performance)
  • 🧹 Chore (miscellaneous changes that don't modify src or test files)

Summary by CodeRabbit

  • New Features
    • Introduced token denylist functionality, allowing tokens to be invalidated and checked for revocation.
  • Bug Fixes
    • Improved token validation to handle revoked or denylisted tokens and enhanced error handling for token extraction.
  • Refactor
    • Updated token parsing and validation logic to use an improved JWT API.
    • Removed the ability to generate new tokens within the utility.

@coderabbitai
Copy link

coderabbitai bot commented May 30, 2025

Walkthrough

The JwtUtil class was refactored to remove JWT token generation and to update token parsing and validation using a new JWT API. Token validation now integrates a denylist check via a newly introduced TokenDenylist component, which manages denylisted JWT IDs using Redis. Method signatures and internal logic were updated for null safety and modern API usage.

Changes

File(s) Change Summary
.../utils/JwtUtil.java Removed token generation method; updated token parsing/validation to new API; added denylist check; improved null safety; adjusted imports.
.../utils/TokenDenylist.java New class: manages JWT denylist using Redis; provides methods to add/check denylisted tokens.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant JwtUtil
    participant TokenDenylist
    participant Redis

    Client->>JwtUtil: validateToken(token)
    JwtUtil->>JwtUtil: parse token & extract claims
    JwtUtil->>TokenDenylist: isTokenDenylisted(jti)
    TokenDenylist->>Redis: check "denied_{jti}" key
    Redis-->>TokenDenylist: return result
    TokenDenylist-->>JwtUtil: denylist status
    JwtUtil-->>Client: return claims or null
Loading

Poem

In the warren of code, a new rule is spun,
No more tokens createdβ€”just checking each one.
If your jti’s listed, the door’s firmly shut,
Redis remembers, no ifs, ands, or buts.
A hop, and a skip, with security tightβ€”
The rabbit approves: sleep well every night! πŸ‡πŸ”’

✨ Finishing Touches
  • πŸ“ Generate Docstrings

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.

❀️ Share
πŸͺ§ Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sonarqubecloud
Copy link

Copy link

@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.

Actionable comments posted: 2

πŸ“œ Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 74d8ebf and 43d3872.

πŸ“’ Files selected for processing (2)
  • src/main/java/com/iemr/mmu/utils/JwtUtil.java (3 hunks)
  • src/main/java/com/iemr/mmu/utils/TokenDenylist.java (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/java/com/iemr/mmu/utils/TokenDenylist.java (1)
src/main/java/com/iemr/mmu/utils/JwtUtil.java (1)
  • Component (14-69)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (java)
πŸ”‡ Additional comments (4)
src/main/java/com/iemr/mmu/utils/TokenDenylist.java (2)

1-22: Well-structured class setup with proper dependency injection.

The class is properly configured as a Spring component with appropriate logger initialization and Redis template autowiring. The key prefix approach is a good practice for namespacing Redis keys.


41-54: Excellent defensive programming with graceful error handling.

The method properly handles Redis failures by returning false to avoid blocking requests, which is a good resilience pattern. The null-safe comparison using Boolean.TRUE.equals() is also a best practice.

src/main/java/com/iemr/mmu/utils/JwtUtil.java (2)

20-29: Good integration of TokenDenylist and improved type safety.

The autowiring of TokenDenylist is properly implemented, and the change to return SecretKey instead of generic Key improves type safety.


31-51: Well-implemented denylist integration with proper null safety.

The token validation correctly checks the denylist after successful parsing, with appropriate null checking for the JWT ID. The integration aligns perfectly with the PR objective of preventing denylisted tokens from being authenticated.

Comment on lines +24 to +39
// Add a token's jti to the denylist with expiration time
public void addTokenToDenylist(String jti, Long expirationTime) {
if (jti == null || jti.trim().isEmpty()) {
return;
}
if (expirationTime == null || expirationTime <= 0) {
throw new IllegalArgumentException("Expiration time must be positive");
}

try {
String key = getKey(jti); // Use helper method to get the key
redisTemplate.opsForValue().set(key, " ", expirationTime, TimeUnit.MILLISECONDS);
} catch (Exception e) {
throw new RuntimeException("Failed to denylist token", e);
}
}
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Consider consistent error handling strategy across methods.

The method throws a RuntimeException on Redis failure, while isTokenDenylisted gracefully handles failures by returning false. This inconsistency could lead to service disruption if Redis is temporarily unavailable.

Consider adopting a uniform approach:

  • Either fail gracefully in both methods (recommended for resilience)
  • Or throw exceptions consistently in both methods

Apply this diff to handle Redis failures gracefully:

 public void addTokenToDenylist(String jti, Long expirationTime) {
     if (jti == null || jti.trim().isEmpty()) {
         return;
     }
     if (expirationTime == null || expirationTime <= 0) {
         throw new IllegalArgumentException("Expiration time must be positive");
     }
 
     try {
         String key = getKey(jti);  // Use helper method to get the key
         redisTemplate.opsForValue().set(key, " ", expirationTime, TimeUnit.MILLISECONDS);
     } catch (Exception e) {
-        throw new RuntimeException("Failed to denylist token", e);
+        logger.error("Failed to add token to denylist for jti: " + jti, e);
+        // Optionally, you could track this failure for monitoring
     }
 }

Also, consider using a more meaningful value instead of a space character:

-        redisTemplate.opsForValue().set(key, " ", expirationTime, TimeUnit.MILLISECONDS);
+        redisTemplate.opsForValue().set(key, "true", expirationTime, TimeUnit.MILLISECONDS);
πŸ€– Prompt for AI Agents
In src/main/java/com/iemr/mmu/utils/TokenDenylist.java between lines 24 and 39,
the addTokenToDenylist method currently throws a RuntimeException on Redis
failure, while isTokenDenylisted handles failures gracefully by returning false.
To ensure consistency and improve resilience, modify addTokenToDenylist to catch
exceptions and handle them gracefully without throwing, similar to
isTokenDenylisted. Additionally, replace the placeholder value " " stored in
Redis with a more meaningful value such as "denied" to improve clarity.

Comment on lines 62 to 68
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
return Jwts.parser()
.verifyWith(getSigningKey())
.build()
.parseSignedClaims(token)
.getPayload();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add exception handling for consistency with validateToken.

The extractAllClaims method doesn't handle exceptions, which could cause runtime errors when called from extractClaim or extractUsername. This is inconsistent with validateToken which catches all exceptions.

Apply this diff to handle exceptions consistently:

 private Claims extractAllClaims(String token) {
+    try {
         return Jwts.parser()
             .verifyWith(getSigningKey())
             .build()
             .parseSignedClaims(token)
             .getPayload();
+    } catch (Exception e) {
+        return null; // Consistent with validateToken behavior
+    }
 }
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
return Jwts.parser()
.verifyWith(getSigningKey())
.build()
.parseSignedClaims(token)
.getPayload();
}
private Claims extractAllClaims(String token) {
try {
return Jwts.parser()
.verifyWith(getSigningKey())
.build()
.parseSignedClaims(token)
.getPayload();
} catch (Exception e) {
return null; // Consistent with validateToken behavior
}
}
πŸ€– Prompt for AI Agents
In src/main/java/com/iemr/mmu/utils/JwtUtil.java between lines 62 and 68, the
extractAllClaims method lacks exception handling, which can cause runtime errors
and is inconsistent with the validateToken method. Modify extractAllClaims to
catch exceptions such as JwtException or general Exception, and handle them
appropriately (e.g., return null or throw a custom exception) to ensure
consistent error handling across methods that parse tokens.

Copy link
Contributor

@srishtigrp78 srishtigrp78 left a comment

Choose a reason for hiding this comment

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

approved.

Copy link
Contributor

@srishtigrp78 srishtigrp78 left a comment

Choose a reason for hiding this comment

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

approved

@srishtigrp78 srishtigrp78 merged commit 60eae06 into develop Jun 2, 2025
8 checks passed
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.

4 participants