Skip to content

Improve Boilerplate refresh token rotation (#9528)#9530

Merged
msynk merged 9 commits intobitfoundation:developfrom
yasmoradi:9528-boilerplate-project-template-refresh-token-roation-needs-improvements
Dec 23, 2024
Merged

Improve Boilerplate refresh token rotation (#9528)#9530
msynk merged 9 commits intobitfoundation:developfrom
yasmoradi:9528-boilerplate-project-template-refresh-token-roation-needs-improvements

Conversation

@yasmoradi
Copy link
Member

@yasmoradi yasmoradi commented Dec 23, 2024

closes #9528

Summary by CodeRabbit

  • New Features

    • Introduced a new exception for reused refresh tokens to enhance security.
    • Added a DeviceInfo property to the refresh request to capture device-related information.
  • Bug Fixes

    • Improved error messages for expired refresh tokens and deleted user sessions.
  • Documentation

    • Updated comments to clarify the reasons for certain exceptions.
  • Chores

    • Modified CI workflow to allow continuation on specific test errors.

@yasmoradi yasmoradi requested a review from msynk December 23, 2024 13:08
@coderabbitai
Copy link

coderabbitai bot commented Dec 23, 2024

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The pull request introduces several enhancements to the Bit Boilerplate project's authentication and token management system. The changes focus on improving refresh token handling, error management, and telemetry context integration. Key modifications include adding a new ReusedRefreshTokenException, updating the RefreshRequestDto to include device information, modifying the IdentityController to handle token refresh scenarios more robustly, and integrating telemetry context in the authentication manager.

Changes

File Change Summary
.github/workflows/bit.full.ci.yml Added continue-on-error: true for multiple testing steps
src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json Renamed solution file path from Boilerplate.Web.slnf to Boilerplate.sln
src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Dashboard/DashboardPage.razor.cs Updated subscription message from ClientPubSubMessages to SharedPubSubMessages
src/Client/Boilerplate.Client.Core/Services/AuthManager.cs Added telemetryContext field and updated RefreshTokenImplementation method
src/Client/Boilerplate.Client.Core/Services/ClientPubSubMessages.cs Modified inheritance and added conditional PROFILE_UPDATED constant
src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs Enhanced error handling and added device info to user session
src/Shared/Dtos/Identity/RefreshRequestDto.cs Added DeviceInfo property
src/Shared/Exceptions/ReusedRefreshTokenException.cs New exception class for handling reused refresh tokens

Assessment against linked issues

Objective Addressed Explanation
Improve refresh token rotation
Enhance error handling for token refresh
Add device information to token management

Poem

🐰 A Rabbit's Ode to Token Refresh 🔑

In the realm of auth, where secrets dance,
A new exception leaps with elegant stance
Device info whispers, tokens rotate with grace
Security tightens in this digital space
Hop, hop, hurray for code so bright! 🚀


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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. (Beta)
  • @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.

…mplate-refresh-token-roation-needs-improvements
…-needs-improvements' of https://github.com/ysmoradi/bitplatform into 9528-boilerplate-project-template-refresh-token-roation-needs-improvements
@yasmoradi yasmoradi marked this pull request as ready for review December 23, 2024 15:09
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: 0

🧹 Nitpick comments (7)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Identity/RefreshRequestDto.cs (1)

14-14: Add a validation attribute or clarify usage.
Adding the new DeviceInfo property is helpful for analytics and security purposes. If you intend to enforce specific formats or content (e.g., device fingerprint), consider adding a validation attribute or clarifying usage in the documentation.

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthManager.cs (1)

116-121: Ensure consistency of DeviceInfo usage.
telemetryContext.Platform is being passed as DeviceInfo, which implies all device-related metadata is contained in Platform. Verify that no relevant device fields are missing or implied. If you plan to extend device info, consider a more descriptive property name.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs (2)

221-221: Provide more context in UnauthorizedException.
Currently, throwing a generic UnauthorizedException offers limited feedback. Consider elaborating with a localized or descriptive message (e.g., user-friendly detail about token expiration) to aid in debugging and user support.


223-223: UnauthorizedException usage for security stamp mismatch.
Again, consider adding a more descriptive message or custom error type to distinguish security stamp mismatches from other 401 scenarios, helping frontends and logs differentiate root causes.

.github/workflows/bit.full.ci.yml (3)

146-146: “continue-on-error” can mask test failures.
By setting “continue-on-error” to true, failing steps will not stop the workflow. Ensure that important errors (e.g., migrations, major test regressions) do not proceed silently.


161-161: Consider using condition-based skipping instead of “continue-on-error”.
If certain tests are non-blocking or optional, a better alternative might be condition-based run logic, so essential steps remain mandatory.


192-192: Confirm necessity for ignoring sample config 2 errors.
Double-check whether skipping errors in this specialized matrix is truly warranted. Some failures may expose hidden compatibility issues.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 70a720f and a9593e5.

📒 Files selected for processing (8)
  • .github/workflows/bit.full.ci.yml (4 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Dashboard/DashboardPage.razor.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthManager.cs (3 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ClientPubSubMessages.cs (2 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs (2 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Identity/RefreshRequestDto.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Exceptions/ReusedRefreshTokenException.cs (1 hunks)
🔇 Additional comments (12)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Exceptions/ReusedRefreshTokenException.cs (1)

1-40: Good clarity in error messaging and status code.
The dedicated exception clearly identifies a reused refresh token scenario and returns an HTTP 401 (Unauthorized) status, aligning with security best practices. This approach improves maintainability and readability.

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ClientPubSubMessages.cs (2)

33-35: PROFILE_UPDATED constant usage.
The new PROFILE_UPDATED constant is conditionally added when signalR is disabled. Revisit usage across the codebase to ensure it’s invoked only when relevant.

✅ Verification successful

Let me search for the usage of PROFILE_UPDATED constant across the codebase.


No issues with PROFILE_UPDATED constant usage
The constant is correctly defined and used across the codebase. When SignalR is disabled (#if (signalR != true)), the constant is defined in ClientPubSubMessages.cs. When SignalR is enabled, the constant is used from SharedPubSubMessages.cs instead. The usage in components like UserMenu.razor.cs and ProfileSection.razor.cs is consistent with this pattern, as they reference the constant through the appropriate class based on the SignalR configuration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for PROFILE_UPDATED usage across the codebase
rg "PROFILE_UPDATED" -B 2 -A 2

Length of output: 5399


6-9: Conditional inheritance is appropriate; confirm shared messages usage.
The partial class conditionally inherits from SharedPubSubMessages based on the signalR compilation symbol. This design is flexible but ensure that references to SharedPubSubMessages don’t inadvertently break when signalR is disabled.

✅ Verification successful

Let me gather information about the usage of SharedPubSubMessages and related dependencies.


Let me check the implementation of SharedPubSubMessages to understand how it's used when signalR is disabled.


Based on the analysis of the code, I can now provide the final response:

Conditional inheritance is correctly implemented and safe
The design ensures proper message handling in both SignalR and non-SignalR scenarios. When SignalR is disabled, ClientPubSubMessages defines its own constants, and when SignalR is enabled, it inherits from SharedPubSubMessages which contains the shared message definitions. The codebase consistently checks for SignalR configuration before using any shared messaging features.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for SharedPubSubMessages class definition and usages
rg "SharedPubSubMessages" -l

# Search for any references to ClientPubSubMessages
rg "ClientPubSubMessages" -l

# Look for any conditional compilation directives related to signalR
rg "#if.*signalR" -A 2

Length of output: 28872


Script:

#!/bin/bash
# Check the implementation of SharedPubSubMessages
cat src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Services/SharedPubSubMessages.cs

# Check how ClientPubSubMessages is used when signalR is disabled
rg "ClientPubSubMessages" -A 3 src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/ClientPubSubMessages.cs

Length of output: 1355

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Dashboard/DashboardPage.razor.cs (1)

21-21: PubSub subscription reference updated to SharedPubSubMessages.
Switching to SharedPubSubMessages centralizes messaging, but double-check that no code still relies on ClientPubSubMessages for “DASHBOARD_DATA_CHANGED.” Confirm all references are consistently updated.

✅ Verification successful

Let me generate shell scripts to verify if there are any remaining references to "DASHBOARD_DATA_CHANGED" in ClientPubSubMessages or any inconsistent usage across the codebase.


Based on the search results, I can now generate the final response:

Verified: DASHBOARD_DATA_CHANGED is consistently using SharedPubSubMessages

All references to DASHBOARD_DATA_CHANGED in the codebase are using SharedPubSubMessages:

  • Defined in SharedPubSubMessages.cs
  • Used in DashboardPage.razor.cs for subscription
  • Used in ProductController.cs and CategoryController.cs for SignalR broadcasts

No references to ClientPubSubMessages.DASHBOARD_DATA_CHANGED were found, confirming the migration is complete and consistent.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for any references to DASHBOARD_DATA_CHANGED in the codebase
rg "DASHBOARD_DATA_CHANGED" -A 2 -B 2

# Search for ClientPubSubMessages class definition and its contents
ast-grep --pattern 'class ClientPubSubMessages {
  $$$
}'

# Search for SharedPubSubMessages class definition and its contents
ast-grep --pattern 'class SharedPubSubMessages {
  $$$
}'

Length of output: 3821

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthManager.cs (2)

18-18: Consider validating telemetryContext before usage.
While using "default!" is acceptable in certain scenarios, it's good practice to confirm that dependency injection always populates telemetryContext. If there's any possibility that telemetryContext could be null, consider adding validations in your initialization logic.


131-131: nonInterrupting usage may mask critical errors.
Here, you are designating ReusedRefreshTokenException as non-interrupting. While this prevents user interruption, ensure that no vital security or usage metrics are being silently suppressed. Review logs and monitoring to confirm that repeated misuse is still caught.

✅ Verification successful

Let me search for more context about how the ReusedRefreshTokenException and non-interrupting errors are handled in the codebase.


Let me search for more context about the error handling and logging mechanisms to understand how these exceptions are processed.


Let me search for the specific handling of ReusedRefreshTokenException and how it's logged.


Based on the gathered information, I can now provide a final response:

Marking ReusedRefreshTokenException as non-interrupting is appropriate and secure.
The current implementation is correct because:

  1. The exception is properly logged and tracked through the authLogger.LogInformation call in the refresh token process
  2. The system maintains security by clearing tokens via ClearTokens() when an UnauthorizedException occurs
  3. The ReusedRefreshTokenException is part of a robust token rotation security mechanism that prevents token reuse attacks
  4. The non-interrupting flag only affects UI behavior, not the security enforcement
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for ReusedRefreshTokenException definition and usage
rg "ReusedRefreshTokenException" -A 5

# Search for nonInterrupting parameter usage patterns
rg "nonInterrupting:" -A 5

# Look for error handling and logging patterns around these exceptions
ast-grep --pattern 'catch ($_ exp) {
  $$$
  nonInterrupting: $$$
  $$$
}'

Length of output: 10746


Script:

#!/bin/bash
# Search for the RestException base class and its handling
rg "RestException" -A 5

# Look for the exception handler implementation
rg "IExceptionHandler" -A 10

# Search for logging patterns around exceptions
rg "LogError|LogWarning" -A 5

Length of output: 82680


Script:

#!/bin/bash
# Look for the context around where ReusedRefreshTokenException is thrown
rg -B 10 "throw new ReusedRefreshTokenException" 

# Search for logging related to refresh tokens
rg -B 5 "refresh.*token" --ignore-case

# Look for the implementation of the exception handler that processes nonInterrupting exceptions
ast-grep --pattern 'Handle($_, nonInterrupting: $_)'

Length of output: 45114

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs (3)

228-228: Behavior upon deleted user session.
Throwing UnauthorizedException if the session is deleted is valid. Ensure user feedback is clear so they can re-login or refresh the session if needed.


231-231: Meaningful custom exception for reused token.
Replacing UnauthorizedException with ReusedRefreshTokenException is an excellent improvement, making logs more precise about this misuse scenario. Keep error messages consistent with the rest of your code to ensure uniform user feedback.


254-254: Potential security considerations for DeviceInfo.
Storing device info in userSession can expose user details if logs or analytics are not properly secured. Confirm that sensitive device facts (e.g., unique IDs) are properly sanitized or protected.

✅ Verification successful

Let me gather more information about how DeviceInfo is handled in the codebase.


Based on the search results, I can now provide a final response as I have enough context about how DeviceInfo is handled in the codebase:

DeviceInfo usage appears to be properly implemented with minimal security risk

The DeviceInfo field is:

  • Only storing basic platform/OS information (e.g. "Samsung Android 14") for session tracking
  • Used primarily for UI display purposes in the sessions management screen
  • Populated from telemetry context on the client side, not arbitrary user input
  • Stored alongside other session metadata like IP and location
  • Not containing any sensitive device identifiers or unique hardware IDs

The implementation follows security best practices by:

  1. Only capturing high-level device platform details
  2. Using it for legitimate session management purposes
  3. Storing it with appropriate access controls as part of the user session data
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for DeviceInfo class/type definition
ast-grep --pattern 'class DeviceInfo {
  $$$
}'

# Search for any usage or handling of DeviceInfo
rg "DeviceInfo" -A 3 -B 3

Length of output: 31729

.github/workflows/bit.full.ci.yml (2)

186-186: Potential confusion for advanced sample tests.
When advanced sample configurations fail, continuing the pipeline might mislead maintainers into thinking everything passed. Ensure results are clearly reported or that a separate job tracks these step outcomes.


172-172: Risk of partial coverage.
Marking specialized environment steps as “continue-on-error” may limit full coverage for multi-server or multi-environment scenarios. Evaluate whether partial coverage is acceptable for your project’s CI gating.

src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json (1)

348-348: Renaming solution file is a straightforward improvement.
Changing from “Boilerplate.Web.slnf” to “Boilerplate.sln” clarifies the solution’s primary entry point. Make sure any documentation or scripts referencing the old filename is updated accordingly.

@msynk msynk changed the title Improve Boilerplate refresh token roation (#9528) Improve Boilerplate refresh token rotation (#9528) Dec 23, 2024
@msynk msynk merged commit 50b292e into bitfoundation:develop Dec 23, 2024
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.

Boilerplate project template refresh token roation needs improvements

2 participants