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 to enhance security by allowing tokens to be invalidated before their natural expiration.
    • Added support for managing token denylist entries, including adding and checking tokens.
  • Bug Fixes

    • Improved handling of token validation to safely manage cases where claims extraction fails.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 30, 2025

"""

Walkthrough

A new TokenDenylist component was introduced to manage JWT token invalidation using Redis. The JwtUtil class was updated to integrate denylist checks during token validation, changing its signing key handling and injecting the denylist dependency. Token validation now returns null if the token is denylisted.

Changes

File(s) Change Summary
src/main/java/com/iemr/tm/utils/JwtUtil.java Injected TokenDenylist, updated token validation to check denylist, switched signing key type to SecretKey.
src/main/java/com/iemr/tm/utils/TokenDenylist.java Added new class managing token denylist in Redis with methods to add tokens with expiration and check denylist.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant JwtUtil
    participant TokenDenylist
    participant Redis

    Client->>JwtUtil: validateToken(token)
    JwtUtil->>JwtUtil: parse JWT, extract jti
    JwtUtil->>TokenDenylist: isTokenDenylisted(jti)
    TokenDenylist->>Redis: check "denied_{jti}" key
    Redis-->>TokenDenylist: return exists/not exists
    TokenDenylist-->>JwtUtil: return denylist status
    alt jti is denylisted
        JwtUtil-->>Client: return null
    else jti is not denylisted
        JwtUtil-->>Client: return claims
    end
Loading

Poem

In the warren of code, a new guard appears,
Denylist in Redis, to quell logout fears.
JWTs checked twice, for safety and peaceβ€”
If a token’s denied, its powers will cease.
With a hop and a skip, security’s tight,
The rabbits sleep soundly through every night!
πŸ‡πŸ”’
"""


πŸ“œ Recent review details

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

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between e3eb3a3 and f332c50.

πŸ“’ Files selected for processing (2)
  • src/main/java/com/iemr/tm/utils/JwtUtil.java (4 hunks)
  • src/main/java/com/iemr/tm/utils/TokenDenylist.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/java/com/iemr/tm/utils/JwtUtil.java
  • src/main/java/com/iemr/tm/utils/TokenDenylist.java
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: style-check / checkstyle
  • GitHub Check: Analyze (java)
✨ 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.

Copy link
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.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/main/java/com/iemr/tm/utils/TokenDenylist.java (1)

35-35: Consider using a more meaningful Redis value.

Using a space character " " as the Redis value works but could be more explicit.

Consider using a more descriptive value:

- redisTemplate.opsForValue().set(key, " ", expirationTime, TimeUnit.MILLISECONDS);
+ redisTemplate.opsForValue().set(key, "DENIED", expirationTime, TimeUnit.MILLISECONDS);
πŸ“œ Review details

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

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 17dcb5a and e3eb3a3.

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

11-18: LGTM! Well-structured component setup.

The class is properly annotated as a Spring component with appropriate logger and Redis template injection. The constant prefix approach for Redis keys is a good practice for namespace isolation.


20-22: LGTM! Clean helper method.

The key generation method properly encapsulates the prefix logic for Redis keys.


42-54: LGTM! Excellent fail-safe strategy.

The method correctly handles Redis failures by returning false to avoid blocking valid requests. The error logging and defensive approach are well-implemented.

src/main/java/com/iemr/tm/utils/JwtUtil.java (6)

6-6: LGTM! Appropriate import for improved type safety.

The import of SecretKey provides better type safety for JWT operations.


22-23: LGTM! Clean dependency injection.

The TokenDenylist component is properly injected for use in token validation.


26-26: LGTM! Improved type safety with SecretKey.

Changing the return type to SecretKey provides better type safety and aligns with JWT library best practices.


61-61: LGTM! Excellent defensive programming.

The null check prevents NullPointerException when claims extraction fails, improving robustness.


65-69: LGTM! Consistent use of new signing key method.

The updated JWT parsing correctly uses the new getSigningKey() method for consistency.


34-53:

Details

❓ Verification inconclusive

Verify JWT token structure requirements.

Ensure that all JWTs in your system include the jti claim, as the denylist functionality depends on it.

Run the following script to check if existing JWT generation code includes jti claims:


🏁 Script executed:

#!/bin/bash
# Description: Search for JWT generation code to verify jti claim usage
# Expected: Find JWT creation code that includes jti claims

# Search for JWT creation/generation patterns
echo "Searching for JWT generation code..."
rg -A 10 -B 5 "Jwts\.builder|jwt.*build|createToken|generateToken"

# Search for jti claim usage
echo -e "\nSearching for jti claim usage..."
rg -A 5 -B 5 "setId\(|\.id\(|jti"

Length of output: 13117


Verify inclusion of jti in your JWT issuance logic

I couldn’t find any Jwts.builder() or generateToken calls in the repo, so it’s unclear whether your token‐creation code ever sets a JTI. Since JwtUtil.validateToken(...) uses claims.getId() to perform denylist checks, you must ensure every JWT your system issues includes a non-null jti.

Please review your token‐generation routine (e.g. in AuthService, SecurityConfig, or any external provider) and confirm that you’re doing something like:

String jti = UUID.randomUUID().toString();
String token = Jwts.builder()
    .setId(jti)
    // … other claims, signWith, etc.
    .compact();

– If tokens come from an external service, verify they ship a jti.
– If you already set the JTI elsewhere, point me to that code.

Comment on lines 57 to 62
public void removeTokenFromDenylist(String jti) {
if (jti != null && !jti.trim().isEmpty()) {
String key = getKey(jti); // Use helper method to get the key
redisTemplate.delete(key);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Add exception handling for consistency.

The remove method lacks exception handling unlike other Redis operations in this class.

Apply this diff to add consistent exception handling:

 public void removeTokenFromDenylist(String jti) {
     if (jti != null && !jti.trim().isEmpty()) {
-        String key = getKey(jti);  // Use helper method to get the key
-        redisTemplate.delete(key);
+        try {
+            String key = getKey(jti);  // Use helper method to get the key
+            redisTemplate.delete(key);
+        } catch (Exception e) {
+            logger.error("Failed to remove token from denylist for jti: " + jti, e);
+            // Don't throw exception to avoid breaking logout/token cleanup flows
+        }
     }
 }
πŸ“ 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
public void removeTokenFromDenylist(String jti) {
if (jti != null && !jti.trim().isEmpty()) {
String key = getKey(jti); // Use helper method to get the key
redisTemplate.delete(key);
}
}
public void removeTokenFromDenylist(String jti) {
if (jti != null && !jti.trim().isEmpty()) {
try {
String key = getKey(jti); // Use helper method to get the key
redisTemplate.delete(key);
} catch (Exception e) {
logger.error("Failed to remove token from denylist for jti: " + jti, e);
// Don't throw exception to avoid breaking logout/token cleanup flows
}
}
}
πŸ€– Prompt for AI Agents
In src/main/java/com/iemr/tm/utils/TokenDenylist.java around lines 57 to 62, the
removeTokenFromDenylist method lacks exception handling unlike other Redis
operations in this class. Wrap the Redis delete operation inside a try-catch
block to catch any exceptions, log the error appropriately, and ensure
consistent exception handling across all Redis interactions in this class.

Comment on lines +25 to +39
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
Contributor

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Improve exception handling consistency.

The method has good input validation but lacks error logging consistency compared to other methods in the class.

Apply this diff to add consistent error logging:

     } catch (Exception e) {
+        logger.error("Failed to add token to denylist for jti: " + jti, e);
         throw new RuntimeException("Failed to denylist token", e);
     }
πŸ“ 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
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);
}
}
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) {
logger.error("Failed to add token to denylist for jti: " + jti, e);
throw new RuntimeException("Failed to denylist token", e);
}
}
πŸ€– Prompt for AI Agents
In src/main/java/com/iemr/tm/utils/TokenDenylist.java between lines 25 and 39,
the addTokenToDenylist method catches exceptions but does not log errors
consistently with other methods. Modify the catch block to log the exception
details using the class logger before throwing the RuntimeException, ensuring
error logging is consistent across the class.

srishtigrp78
srishtigrp78 previously approved these changes May 30, 2025
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.

looks fine

@sonarqubecloud
Copy link

@drtechie drtechie requested a review from ravishanigarapu May 30, 2025 12:35
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 0ea592a into develop Jun 2, 2025
7 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.

3 participants