Skip to content

Feature: redis cluster#1

Open
urkishan wants to merge 6 commits intomasterfrom
feature/redis-cluster
Open

Feature: redis cluster#1
urkishan wants to merge 6 commits intomasterfrom
feature/redis-cluster

Conversation

@urkishan
Copy link
Copy Markdown
Owner

@urkishan urkishan commented Jun 29, 2023

Summary by CodeRabbit

  • New Features

    • Added explicit token ID ↔ UUID linkage and a method to renew tokens by ID and expiration.
  • Improvements

    • Standardized identifier terminology from "uid" to "uuid" across token flows.
    • Added efficient token key scanning with fallback for large stores.
    • Extended Redis configuration to support password and cluster modes.
  • Bug Fixes

    • Improved refresh-token expiry handling and robustness in retrieval.
  • Documentation

    • Updated tests and docs to reflect uuid terminology and token management changes.

✏️ Tip: You can customize this high-level summary in your review settings.

@urkishan urkishan force-pushed the feature/redis-cluster branch from da0510c to cf0056f Compare June 30, 2023 13:43
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jul 25, 2024

Walkthrough

Renames uid → uuid across the JWT sessions adapters and tokens, adds JTI↔UUID helpers, adds Redis SCAN support and redis_cluster/password options, and introduces methods for updating refresh expirations and explicit refresh UUID management.

Changes

Cohort / File(s) Change Summary
Redis store adapter
lib/jwt_sessions/store_adapters/redis_store_adapter.rb
Replaced uid with uuid across public APIs; added refresh_uuid, set_refresh_uuid, jti_key, scan_keys, update_refresh_expiry, and configure_redis_client params (redis_password, redis_cluster); switched key helpers and iteration to uuid-based semantics.
Abstract / Memory adapters
lib/jwt_sessions/store_adapters/abstract_store_adapter.rb, lib/jwt_sessions/store_adapters/memory_store_adapter.rb
Renamed _uid_uuid in method signatures and helpers; added/updated refresh management methods to use uuid.
Token/session classes
lib/jwt_sessions/access_token.rb, lib/jwt_sessions/refresh_token.rb, lib/jwt_sessions/session.rb
Updated methods and internal calls to use uuid instead of uid; added expiry/update helpers and renew_tokens-style behavior where applicable.
Authorization / Rails integration
lib/jwt_sessions/authorization.rb, lib/jwt_sessions/rails_authorization.rb
Minor adjustments to header/token retrieval and request method access; updated to align with uuid naming.
Tests
test/units/jwt_sessions/store_adapters/test_memory_store_adapter.rb, test/units/jwt_sessions/test_access_token.rb, test/units/jwt_sessions/test_refresh_token.rb, test/units/jwt_sessions/test_session.rb
Updated tests to reflect uuid naming, access_uuid rename, and added tests for update_expiry/update_refresh_expiry behaviors.
Misc / manifest
.gitignore
Minor addition: ignore .idea.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

Areas to focus on during review:

  • Public API signature changes in store adapters (ensure callers updated).
  • Redis client configuration: redis_password and redis_cluster handling and fallbacks.
  • scan_keys implementation and SCAN fallback correctness (pattern, cursor handling).
  • JTI ↔ UUID linkage: jti_key, refresh_uuid, set_refresh_uuid, and expiry behavior.
  • Tests that validate rename coverage and new expiry/update behaviors.

Poem

🐇 I chew through code, nibble a clue,
From uid to uuid I hop through the dew.
Keys now match, tokens hum true,
JTI and UUID dancing anew.
A tiny hop — sessions refreshed, we’re through! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The PR title 'Feature: redis cluster' is vague and incomplete. While redis cluster support is added, the primary changes are a comprehensive refactoring from 'uid' to 'uuid' nomenclature across all public methods and constants. The title does not reflect this major change. Consider a more descriptive title that captures the main refactoring, such as 'Refactor: Replace uid with uuid nomenclature and add redis cluster support' to better reflect the scope of changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/redis-cluster

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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

Outside diff range, codebase verification and nitpick comments (3)
lib/jwt_sessions/refresh_token.rb (3)

52-53: Update necessary for destroy method calls to match the new signature

The destroy method in lib/jwt_sessions/refresh_token.rb has been updated with the new parameters. However, there are calls to destroy in other files that still use the old parameter names. Please update these calls to match the new signature:

  • lib/jwt_sessions/session.rb
  • test/units/jwt_sessions/test_access_token.rb
  • test/units/jwt_sessions/test_refresh_token.rb
Analysis chain

LGTM! But verify the function usage in the codebase.

The changes in the destroy method are consistent and correctly applied.

However, ensure that all calls to destroy match the new signature.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all calls to `destroy` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type ruby -A 5 $'def destroy(uuid, store, namespace)'

Length of output: 59


Script:

#!/bin/bash
# Description: Verify all calls to `destroy` match the new signature.

# Search for the definition of the destroy method with the new signature.
rg --type ruby 'def destroy(uuid, store, namespace)'

# Search for calls to the destroy method to ensure they match the new signature.
rg --type ruby 'destroy('

Length of output: 149


Script:

#!/bin/bash
# Description: Verify all calls to `destroy` match the new signature.

# Search for the definition of the destroy method with the new signature.
rg --type ruby 'def destroy\(uuid, store, namespace\)'

# Search for calls to the destroy method to ensure they match the new signature.
rg --type ruby 'destroy\('

Length of output: 961


72-81: Ensure all calls to update match the new signature.

The test file test/units/jwt_sessions/test_refresh_token.rb uses new_access_uid instead of new_access_uuid. Update this to ensure consistency:

  • test/units/jwt_sessions/test_refresh_token.rb:
    • Change new_access_uid to new_access_uuid in the update method call.

Other occurrences in lib/jwt_sessions/session.rb are correct.

Analysis chain

LGTM! But verify the function usage in the codebase.

The changes in the update method are consistent and correctly applied.

However, ensure that all calls to update match the new signature.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all calls to `update` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type ruby -A 5 $'def update(access_uuid, access_expiration, csrf)'

Length of output: 72


Script:

#!/bin/bash
# Description: Verify all calls to `update` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type ruby '\.update\('

Length of output: 327


Script:

#!/bin/bash
# Description: Verify the parameter names in the calls to the `update` method.

# Check the specific lines in the files where `update` is called.
rg --type ruby -A 2 -B 2 '\.update\(' test/units/jwt_sessions/test_refresh_token.rb lib/jwt_sessions/session.rb

Length of output: 1275


46-49: Update Required: Ensure all calls to find match the new signature

The changes in the find method are consistent and correctly applied in lib/jwt_sessions/session.rb. However, there are multiple instances in the test files where the old signature with uid is still used. Please update these calls to match the new signature with uuid.

  • Files with old signature usage:
    • test/units/jwt_sessions/test_session.rb
    • test/units/jwt_sessions/test_refresh_token.rb
Analysis chain

LGTM! But verify the function usage in the codebase.

The changes in the find method are consistent and correctly applied.

However, ensure that all calls to find match the new signature.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all calls to `find` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type ruby -A 5 $'def find(uuid, store, namespace = nil, first_match: false)'

Length of output: 82


Script:

#!/bin/bash
# Description: Verify all calls to `find` match the new signature.

# Search for the method definition to confirm its presence.
rg --type ruby 'def find('

# Search for all calls to the `find` method.
rg --type ruby '\.find('

Length of output: 189


Script:

#!/bin/bash
# Description: Verify all calls to `find` match the new signature.

# Search for the method definition to confirm its presence.
rg --type ruby 'def find\('

# Search for all calls to the `find` method.
rg --type ruby '\.find\('

Length of output: 2853

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between ff6bcd0 and e60eb78.

Files selected for processing (13)
  • .gitignore (1 hunks)
  • lib/jwt_sessions/access_token.rb (2 hunks)
  • lib/jwt_sessions/authorization.rb (2 hunks)
  • lib/jwt_sessions/rails_authorization.rb (1 hunks)
  • lib/jwt_sessions/refresh_token.rb (2 hunks)
  • lib/jwt_sessions/session.rb (9 hunks)
  • lib/jwt_sessions/store_adapters/abstract_store_adapter.rb (1 hunks)
  • lib/jwt_sessions/store_adapters/memory_store_adapter.rb (3 hunks)
  • lib/jwt_sessions/store_adapters/redis_store_adapter.rb (4 hunks)
  • test/units/jwt_sessions/store_adapters/test_memory_store_adapter.rb (1 hunks)
  • test/units/jwt_sessions/test_access_token.rb (1 hunks)
  • test/units/jwt_sessions/test_refresh_token.rb (2 hunks)
  • test/units/jwt_sessions/test_session.rb (7 hunks)
Files skipped from review due to trivial changes (4)
  • .gitignore
  • lib/jwt_sessions/rails_authorization.rb
  • lib/jwt_sessions/store_adapters/abstract_store_adapter.rb
  • test/units/jwt_sessions/test_access_token.rb
Additional comments not posted (72)
lib/jwt_sessions/access_token.rb (9)

5-5: Update the attr_reader to use uuid.

The attr_reader has been updated to use uuid instead of uid.


7-11: Update the initialize method to use uuid.

The initialize method now uses uuid instead of uid. Ensure that all instances of uid in the payload are updated to uuid.


16-16: Update the destroy method to use uuid.

The destroy method now uses uuid instead of uid. Ensure that store.destroy_access correctly handles uuid.


19-20: Rename refresh_uid= to refresh_uuid=.

The method refresh_uid= has been renamed to refresh_uuid= and updates the payload correctly.


23-24: Rename refresh_uid to refresh_uuid.

The method refresh_uid has been renamed to refresh_uuid and accesses the payload correctly.


34-34: Update the create method to use uuid.

The create method now uses uuid instead of uid. Ensure that store.persist_access correctly handles uuid.


38-39: Update the class method destroy to use uuid.

The class method destroy now uses uuid instead of uid. Ensure that store.destroy_access correctly handles uuid.


45-48: Update the find method to use uuid.

The find method now uses uuid instead of uid. Ensure that store.fetch_access correctly handles uuid.


53-54: Update the build_with_token_attrs method to use uuid.

The build_with_token_attrs method now uses uuid instead of uid. Ensure that the method correctly handles uuid.

test/units/jwt_sessions/test_refresh_token.rb (2)

7-7: Update the attr_reader to use access_uuid.

The attr_reader has been updated to use access_uuid instead of access_uid.


32-37: Add a new test method test_update_expiry.

A new test method test_update_expiry has been added to test the functionality of updating the expiration time of a token. Ensure that the test covers all relevant scenarios.

test/units/jwt_sessions/store_adapters/test_memory_store_adapter.rb (3)

20-21: Update the test_persist_and_fetch_access method to use uuid.

The test_persist_and_fetch_access method now uses uuid instead of uid. Ensure that the method correctly handles uuid.


30-37: Update the test_persist_and_fetch_refresh method to use uuid.

The test_persist_and_fetch_refresh method now uses uuid instead of uid. Ensure that the method correctly handles uuid.


56-56: Update the test_update_refresh method to use uuid.

The test_update_refresh method now uses uuid instead of uid. Ensure that the method correctly handles uuid.

lib/jwt_sessions/refresh_token.rb (4)

39-40: LGTM! But verify the function usage in the codebase.

The changes in the all method are consistent and correctly applied.

However, ensure that all calls to all match the new signature.

Verification successful

We need to re-verify the usage of the all method to ensure it matches the new signature. Let's search for all occurrences of the all method in the codebase.


We need to correct the regex pattern and re-run the search to verify the usage of the all method.


Verified: The function usage matches the new signature.

The all method is consistently called with the new signature (namespace, store) across the codebase.

  • lib/jwt_sessions/session.rb
  • test/units/jwt_sessions/test_refresh_token.rb
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all calls to `all` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type ruby -A 5 $'def all(namespace, store)'

Length of output: 49


Script:

#!/bin/bash
# Description: Verify all calls to `all` match the new signature.

# Test: Search for the function usage in a more general way. Expect: Occurrences of the `all` method usage.
rg --type ruby 'all('

Length of output: 82


Script:

#!/bin/bash
# Description: Verify all calls to `all` match the new signature.

# Test: Search for the function usage with corrected regex pattern. Expect: Occurrences of the `all` method usage.
rg --type ruby 'all\('

Length of output: 578


85-90: LGTM! But verify the function usage in the codebase.

The new update_expiry method is correctly implemented and consistent with the existing code.

However, ensure that all calls to update_expiry are correctly implemented.

Verification successful

LGTM! The update_expiry method is correctly implemented and its usage is verified in the codebase.

The method is utilized in the following files:

  • test/units/jwt_sessions/test_refresh_token.rb
  • test/units/jwt_sessions/test_session.rb
  • lib/jwt_sessions/session.rb

The method is also being tested, ensuring its correct functionality.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all calls to `update_expiry` are correctly implemented.

# Test: Search for the function usage. Expect: Only occurrences of the new method.
rg --type ruby -A 5 $'def update_expiry(uuid, expiration)'

Length of output: 59


Script:

#!/bin/bash
# Description: Verify all calls to `update_expiry` are correctly implemented.

# Test: Search for the function calls. Expect: All occurrences of the new method.
rg --type ruby -A 5 'update_expiry('

Length of output: 117


Script:

#!/bin/bash
# Description: Verify all calls to `update_expiry` are correctly implemented.

# Test: Search for the function calls. Expect: All occurrences of the new method.
rg --type ruby -A 5 'update_expiry\('

Length of output: 1602


5-19: LGTM! But verify the function usage in the codebase.

The changes in the initialize method are consistent and correctly applied.

However, ensure that all calls to initialize match the new signature.

Verification successful

Let's correct the regex syntax error and re-run the verification.


Let's correct the regex by escaping the parentheses and re-run the verification.


Let's simplify the search pattern to just look for the initialize method and manually inspect the results.


LGTM! But verify the function usage in the codebase.

The changes in the initialize method are consistent and correctly applied.

  • The initialize method in refresh_token.rb matches the new signature.
  • Other initialize methods in different files have different signatures, which is expected.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all calls to `initialize` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type ruby -A 5 $'def initialize(csrf, access_uuid, access_expiration, store, options = {})'

Length of output: 324


Script:

#!/bin/bash
# Description: Verify all calls to `initialize` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type ruby -A 5 'def initialize(csrf, access_uuid, access_expiration, store, options = {})'

Length of output: 324


Script:

#!/bin/bash
# Description: Verify all calls to `initialize` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type ruby -A 5 'def initialize\(csrf, access_uuid, access_expiration, store, options = {}\)'

Length of output: 329


Script:

#!/bin/bash
# Description: Verify all calls to `initialize` match the new signature.

# Test: Search for the function usage. Expect: Occurrences of the `initialize` method.
rg --type ruby -A 5 'def initialize'

Length of output: 2969


Line range hint 23-31:
LGTM! But verify the function usage in the codebase.

The changes in the create method are consistent and correctly applied.

However, ensure that all calls to create match the new signature.

Verification successful

Verification Successful: All calls to the create method match the new signature.

  • lib/jwt_sessions/refresh_token.rb:
    • The create method is defined with the new parameter names.
    • Calls to create use the new parameter names correctly.
  • lib/jwt_sessions/session.rb:
    • Calls to RefreshToken.create use the new parameter names correctly.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all calls to `create` match the new signature.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type ruby -A 5 $'def create(csrf, access_uuid, access_expiration, store, payload, namespace, expiration = JWTSessions.refresh_expiration)'

Length of output: 144


Script:

#!/bin/bash
# Description: Verify all calls to `create` method match the new signature.

# Test: Search for all calls to the `create` method in the codebase.
rg --type ruby 'create('

Length of output: 91


Script:

#!/bin/bash
# Description: Verify all calls to `create` method match the new signature.

# Test: Search for all calls to the `create` method in the codebase with corrected regex pattern.
rg --type ruby 'create\('

Length of output: 1474


Script:

#!/bin/bash
# Description: Verify the calls to `create` method in relevant files match the new signature.

# Test: Extract lines around the `create` calls in `lib/jwt_sessions/refresh_token.rb` and `lib/jwt_sessions/session.rb`.
rg --type ruby -A 3 'create\(' lib/jwt_sessions/refresh_token.rb lib/jwt_sessions/session.rb

Length of output: 854

lib/jwt_sessions/store_adapters/redis_store_adapter.rb (17)

23-25: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


28-31: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


34-39: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


42-52: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


55-61: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


64-68: LGTM!

The new method enhances the functionality for managing token expiration.


69-74: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


78-80: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


83-85: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


87-89: LGTM!

The new method enhances the functionality for managing token UUIDs.


91-93: LGTM!

The new method enhances the functionality for managing token UUIDs with expiration.


Line range hint 97-115: LGTM!

The additional parameters enhance the configuration options for connecting to a Redis instance.


129-131: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


133-136: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


138-140: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


143-145: LGTM!

The changes improve semantic clarity by using uuid instead of uid.


147-149: LGTM!

The changes improve semantic clarity by using uuid instead of uid.

lib/jwt_sessions/store_adapters/memory_store_adapter.rb (10)

15-17: LGTM!

The parameter renaming from uid to uuid improves clarity and consistency.


20-22: LGTM!

The parameter renaming from uid to uuid improves clarity and consistency.


25-33: LGTM!

The parameter renaming from uid to uuid improves clarity and consistency.


37-43: LGTM!

The parameter renaming from uid to uuid improves clarity and consistency.


48-54: LGTM!

The parameter renaming from uid to uuid improves clarity and consistency.


58-60: LGTM!

The method correctly updates the expiration time of the refresh token.


70-71: LGTM!

The parameter renaming from uid to uuid improves clarity and consistency.


74-75: LGTM!

The parameter renaming from uid to uuid improves clarity and consistency.


78-79: LGTM!

The method correctly retrieves the UUID based on the provided key and namespace.


82-83: LGTM!

The method correctly stores the refresh token associated with a key and expiration time in the storage.

lib/jwt_sessions/authorization.rb (5)

70-70: LGTM!

The change from double quotes to single quotes improves consistency in string formatting.


74-74: LGTM!

The change from double quotes to single quotes improves consistency in string formatting.


78-78: LGTM!

The change from double quotes to single quotes improves consistency in string formatting.


101-101: LGTM!

The change from double quotes to single quotes improves consistency in string formatting.


106-109: LGTM!

The enhancement to include a fallback mechanism that checks the env of the request headers improves the robustness of the token retrieval process.

lib/jwt_sessions/session.rb (17)

35-40: LGTM!

The method correctly facilitates the renewal of tokens based on a given jti and expiration time.


59-59: LGTM!

The change from refresh_by_uid to refresh_by_uuid improves consistency with the new identifier schema.


64-69: LGTM!

The change from uid to uuid improves consistency with the new identifier schema.


74-75: LGTM!

The change from uid to uuid improves consistency with the new identifier schema.


80-81: LGTM!

The change from uid to uuid improves consistency with the new identifier schema.


85-88: LGTM!

The method correctly flushes the session by refresh token UUID.


93-96: LGTM!

The method correctly flushes the session by refresh token JTI.


103-103: LGTM!

The change from access_uid to access_uuid improves consistency with the new identifier schema.


113-113: LGTM!

The change from access_uid to access_uuid improves consistency with the new identifier schema.


121-121: LGTM!

The change from access_uid to access_uuid improves consistency with the new identifier schema.


127-131: LGTM!

The change from uid to uuid improves consistency with the new identifier schema.


136-139: LGTM!

The method correctly updates the expiration time of the refresh token.


141-142: LGTM!

The method correctly retrieves the UUID based on the provided key and namespace.


145-147: LGTM!

The method correctly stores the refresh token associated with a key and expiration time in the storage.


159-161: LGTM!

The change from uid to uuid improves consistency with the new identifier schema.


176-177: LGTM!

The change from uid to uuid improves consistency with the new identifier schema.


183-184: **LGTM!

test/units/jwt_sessions/test_session.rb (5)

94-94: LGTM! Variable uid renamed to uuid.

The variable renaming is consistent and correctly used.


107-107: LGTM! Variable uid renamed to uuid.

The variable renaming is consistent and correctly used.


121-121: LGTM! Variable uid renamed to uuid.

The variable renaming is consistent and correctly used.


134-139: LGTM! Function and variable names updated.

The function name and variable renaming are consistent and correctly used.


338-345: New function update_refresh_expiry added.

The function correctly updates the expiry of a refresh token and asserts that an unauthorized error is raised when attempting to find a refresh token with an outdated UID.

expiration: Time.now.to_i + 3600
)
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Update other methods to use access_uuid.

The other methods still use access_uid. Ensure that all instances of access_uid are updated to access_uuid for consistency.

-    assert_equal new_access_uid, token.access_uid
+    assert_equal new_access_uid, token.access_uuid

-    assert_equal found_token.access_uid, token.access_uid
+    assert_equal found_token.access_uuid, token.access_uuid

-    assert_equal [token.token, token_2.token].sort, JWTSessions::RefreshToken.all(nil, JWTSessions.token_store).map(&:token).sort
+    assert_equal [token.token, token_2.token].sort, JWTSessions::RefreshToken.all(nil, JWTSessions.token_store).map(&:token).sort

Committable suggestion was skipped due to low confidence.

Comment on lines +20 to +21
store.persist_access("uuid", "csrf", Time.now.to_i + 3600)
assert_equal({ csrf: "csrf" }, store.fetch_access("uuid"))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Update other methods to use uuid.

The other methods still use uid. Ensure that all instances of uid are updated to uuid for consistency.

-    store.persist_access("uid", "csrf", Time.now.to_i + 3600)
+    store.persist_access("uuid", "csrf", Time.now.to_i + 3600)

-    store.persist_access("uid", "csrf", Time.now.to_i - 3600)
+    store.persist_access("uuid", "csrf", Time.now.to_i - 3600)

-    store.persist_refresh(
-      uid: "uid",
+    store.persist_refresh(
+      uuid: "uuid",

-    refresh = store.fetch_refresh("uid", "")
+    refresh = store.fetch_refresh("uuid", "")

Also applies to: 23-24, 42-44, 49-49

Copy link
Copy Markdown

@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

🧹 Nitpick comments (4)
lib/jwt_sessions/store_adapters/redis_store_adapter.rb (4)

34-40: first_match parameter on fetch_refresh is unused

fetch_refresh(uuid, namespace, first_match = false) ignores first_match, while the memory adapter implements cross-namespace behavior when first_match is true.

If the Redis adapter is intentionally not supporting that mode, consider renaming the parameter to _first_match (or similar) to make it explicit and avoid confusion. If the behavior is expected to match the memory adapter, this method would need a corresponding implementation.


42-68: Refresh persistence/update flow is coherent; consider taming parameter list

persist_refresh, update_refresh, and update_refresh_expiry work together coherently: they use full_refresh_key, write the same fields as defined in REFRESH_KEYS, and consistently rely on expireat with an absolute expiration timestamp, which matches the rest of the codebase.

The 6-argument keyword signature on persist_refresh is what RuboCop flagged. If that becomes painful to maintain, consider wrapping the refresh attributes into a small value object or a single options hash, but this is not blocking.


97-118: Redis cluster/password configuration: confirm expectations and consider non-cluster password use

The new configure_redis_client logic looks sane overall:

  • It guards against mixing redis_url with host/port/db components.
  • It reuses build_redis_url when redis_url is not provided.
  • It switches between { cluster: redis_url, password: redis_password, driver: :hiredis } and { url: redis_url, driver: :hiredis } based on redis_cluster.

Two points to double‑check:

  1. Password usage in non-cluster mode
    redis_password is only applied when redis_cluster is true; non-cluster setups must embed the password in redis_url or REDIS_URL. If consumers expect redis_password to work in both modes, you might want to also include it in the non-cluster config.

  2. Cluster URL shape
    Ensure upstream code passes redis_url in the form expected by Redis.new(cluster: ...) for cluster mode (e.g., array of node URLs vs single URL), to avoid surprises at runtime.

Both are behavioral questions rather than correctness issues in this diff, but worth verifying against how the gem is documented and used.


131-138: Key patterns, SCAN, and helper methods are generally solid; minor nits only

  • full_refresh_key, refresh_key, and uuid_from_key are internally consistent and compatible with the patterns used by scan_keys and all_refresh_tokens.
  • scan_keys implements a proper SCAN loop and supports the “find-first” case via count: 1, which keeps first_refresh_key efficient.

Minor, non-blocking observations:

  • The rescue block in scan_keys logs “falling back to direct key lookup,” but the current implementation simply returns []. If you no longer fall back to KEYS, consider updating the message to match behavior.
  • If namespaces or prefixes can contain underscores, uuid_from_key’s key.split("_").last remains safe as long as UUIDs never include underscores (which is a reasonable assumption).

These are all minor polish points; the core logic looks good.

Also applies to: 140-159, 161-171

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e60eb78 and 6214f42.

📒 Files selected for processing (1)
  • lib/jwt_sessions/store_adapters/redis_store_adapter.rb (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
lib/jwt_sessions/store_adapters/redis_store_adapter.rb (4)
lib/jwt_sessions/store_adapters/memory_store_adapter.rb (10)
  • fetch_access (15-18)
  • persist_access (20-23)
  • fetch_refresh (25-35)
  • persist_refresh (37-46)
  • update_refresh (48-56)
  • update_refresh_expiry (58-60)
  • all_refresh_tokens (62-68)
  • destroy_refresh (70-72)
  • destroy_access (74-76)
  • refresh_uuid (78-80)
lib/jwt_sessions/store_adapters/abstract_store_adapter.rb (9)
  • fetch_access (5-38)
  • fetch_access (6-8)
  • persist_access (10-12)
  • fetch_refresh (15-17)
  • persist_refresh (19-21)
  • update_refresh (23-25)
  • all_refresh_tokens (27-29)
  • destroy_refresh (31-33)
  • destroy_access (35-37)
lib/jwt_sessions.rb (1)
  • access_expiration (131-133)
lib/jwt_sessions/access_token.rb (2)
  • refresh_uuid (19-21)
  • refresh_uuid (23-25)
🪛 RuboCop (1.81.7)
lib/jwt_sessions/store_adapters/redis_store_adapter.rb

[convention] 42-42: Avoid parameter lists longer than 5 parameters. [6/5]

(Metrics/ParameterLists)


[convention] 97-97: Avoid parameter lists longer than 5 parameters. [6/5]

(Metrics/ParameterLists)

🔇 Additional comments (1)
lib/jwt_sessions/store_adapters/redis_store_adapter.rb (1)

8-32: UUID migration and access token storage look consistent

The switch to access_uuid in REFRESH_KEYS and the fetch_access / persist_access / access_key helpers is internally consistent and matches the UUID-based interface used by the abstract and memory adapters. Expiration with expireat is aligned with the rest of the library’s timestamp-based expirations.

Comment on lines 70 to 75
def all_refresh_tokens(namespace)
keys_in_namespace = storage.keys(refresh_key("*", namespace))
keys_in_namespace = scan_keys(refresh_key("*", namespace))
(keys_in_namespace || []).each_with_object({}) do |key, acc|
uid = uid_from_key(key)
acc[uid] = fetch_refresh(uid, namespace)
uuid = uuid_from_key(key)
acc[uuid] = fetch_refresh(uuid, namespace)
end
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

jwt_sessions ruby redis store adapter all_refresh_tokens namespace

💡 Result:

Short answer — yes. Configure the gem to use Redis as the token store, pass a prefix/redis URL in JWTSessions.token_store, and use Session.new(namespace: '...') to group (namespace) sessions so refresh tokens for that namespace are stored/queried together.

Example (config/initializers/jwt_sessions.rb):
JWTSessions.token_store = :redis, {
redis_url: ENV.fetch("REDIS_URL", "redis://127.0.0.1:6379/0"),
token_prefix: "jwt_" # optional key prefix
}

create/session ops with namespace

session = JWTSessions::Session.new(payload: {user_id: user.id}, namespace: "user:#{user.id}")
tokens = session.login

Useful APIs:

  • Session.new(namespace: "...") groups sessions; RefreshToken.all(namespace, store) lists refresh tokens for that namespace. Use session.flush_namespaced / session.flush_namespaced_access_tokens to remove tokens by namespace. [1][2][3]

Sources:
[1] jwt_sessions README (token_store, token_prefix, namespace, Session API).
[2] jwt_sessions (rubydoc) — JWTSessions.token_store and StoreAdapters.
[3] JWTSessions::Session docs — refresh/flush and RefreshToken.all usage.


🏁 Script executed:

find . -type f -name "*redis*adapter*" | head -20

Repository: urkishan/jwt_sessions

Length of output: 190


🏁 Script executed:

find . -type f -name "*store*adapter*" | head -20

Repository: urkishan/jwt_sessions

Length of output: 415


🏁 Script executed:

git ls-files | grep -i adapter | head -20

Repository: urkishan/jwt_sessions

Length of output: 403


🏁 Script executed:

cat -n lib/jwt_sessions/store_adapters/redis_store_adapter.rb 2>/dev/null | head -100

Repository: urkishan/jwt_sessions

Length of output: 4112


🏁 Script executed:

ls -la lib/jwt_sessions/store_adapters/ 2>/dev/null || echo "Path not found, searching..."
find . -path "*store_adapters*" -type f 2>/dev/null

Repository: urkishan/jwt_sessions

Length of output: 747


🏁 Script executed:

git ls-files | grep store_adapter

Repository: urkishan/jwt_sessions

Length of output: 403


🏁 Script executed:

git ls-files | grep -E "redis|adapter|store"

Repository: urkishan/jwt_sessions

Length of output: 434


🏁 Script executed:

pwd && git ls-files | head -30

Repository: urkishan/jwt_sessions

Length of output: 1033


🏁 Script executed:

find . -type f -name "*.rb" | grep -i redis | head -10

Repository: urkishan/jwt_sessions

Length of output: 190


🏁 Script executed:

find . -type f -name "*.rb" | head -50

Repository: urkishan/jwt_sessions

Length of output: 2690


🏁 Script executed:

find . -type d -name "jwt_sessions" 2>/dev/null

Repository: urkishan/jwt_sessions

Length of output: 109


🏁 Script executed:

ls -la && echo "---" && find . -maxdepth 3 -type d | head -30

Repository: urkishan/jwt_sessions

Length of output: 1349


🏁 Script executed:

find . -name "*redis_store*" -o -name "*memory_store*" 2>/dev/null | head -20

Repository: urkishan/jwt_sessions

Length of output: 318


🏁 Script executed:

ls -laR | grep -E "(redis|adapter)" | head -30

Repository: urkishan/jwt_sessions

Length of output: 712


🏁 Script executed:

find . -type f \( -name "*.rb" -o -name "*.js" -o -name "*.py" \) 2>/dev/null | wc -l

Repository: urkishan/jwt_sessions

Length of output: 67


🏁 Script executed:

find . -type f \( -name "*.rb" -o -name "*.js" -o -name "*.py" \) 2>/dev/null | head -100

Repository: urkishan/jwt_sessions

Length of output: 3318


🏁 Script executed:

rg "def all_refresh_tokens" -A 10 2>/dev/null

Repository: urkishan/jwt_sessions

Length of output: 2957


🏁 Script executed:

rg "all_refresh_tokens" 2>/dev/null

Repository: urkishan/jwt_sessions

Length of output: 659


🏁 Script executed:

rg "refresh_key" 2>/dev/null

Repository: urkishan/jwt_sessions

Length of output: 1502


🏁 Script executed:

rg "MemoryStoreAdapter" 2>/dev/null

Repository: urkishan/jwt_sessions

Length of output: 561


🏁 Script executed:

rg "RedisStoreAdapter" 2>/dev/null

Repository: urkishan/jwt_sessions

Length of output: 1985


🏁 Script executed:

git log --oneline -10 2>/dev/null || echo "Not a git repo or no history"

Repository: urkishan/jwt_sessions

Length of output: 128


🏁 Script executed:

file . && stat . | head -5

Repository: urkishan/jwt_sessions

Length of output: 109


🏁 Script executed:

echo "Current directory:" && pwd && echo "Contents:" && ls -la

Repository: urkishan/jwt_sessions

Length of output: 1012


🏁 Script executed:

cat lib/jwt_sessions/store_adapters/redis_store_adapter.rb 2>&1

Repository: urkishan/jwt_sessions

Length of output: 5604


🏁 Script executed:

test -f "lib/jwt_sessions/store_adapters/redis_store_adapter.rb" && echo "File exists" || echo "File not found"

Repository: urkishan/jwt_sessions

Length of output: 76


🏁 Script executed:

ls lib/ 2>&1 || ls . 2>&1 | head -20

Repository: urkishan/jwt_sessions

Length of output: 93


🏁 Script executed:

cat -n lib/jwt_sessions/store_adapters/redis_store_adapter.rb | sed -n '139,157p'

Repository: urkishan/jwt_sessions

Length of output: 825


🏁 Script executed:

cat -n lib/jwt_sessions/store_adapters/memory_store_adapter.rb

Repository: urkishan/jwt_sessions

Length of output: 4283


🏁 Script executed:

cat -n lib/jwt_sessions/store_adapters/redis_store_adapter.rb | sed -n '1,180p'

Repository: urkishan/jwt_sessions

Length of output: 6857


🏁 Script executed:

cat -n test/units/jwt_sessions/store_adapters/test_redis_store_adapter.rb

Repository: urkishan/jwt_sessions

Length of output: 3285


🏁 Script executed:

cat -n test/units/jwt_sessions/store_adapters/test_memory_store_adapter.rb

Repository: urkishan/jwt_sessions

Length of output: 3841


🏁 Script executed:

rg "all_refresh_tokens" -B2 -A8 test/

Repository: urkishan/jwt_sessions

Length of output: 2100


🏁 Script executed:

rg "all_refresh_tokens.*nil" test/

Repository: urkishan/jwt_sessions

Length of output: 47


🏁 Script executed:

cat -n lib/jwt_sessions/refresh_token.rb

Repository: urkishan/jwt_sessions

Length of output: 4019


🏁 Script executed:

python3 << 'EOF'
# Simulate the behavior
def full_refresh_key(prefix, uuid, namespace):
    return f"{prefix}_{namespace}_refresh_{uuid}"

def refresh_key(uuid, namespace):
    if not namespace or namespace == "":
        namespace = "*"
    return full_refresh_key("jwt", uuid, namespace)

# Simulating scan results when calling refresh_key("*", None)
print("SCAN pattern when namespace=None:")
pattern = refresh_key("*", None)
print(f"  Pattern: {pattern}")
print(f"  Would match keys like: jwt_ns1_refresh_uuid1, jwt_ns2_refresh_uuid2")

# Simulating fetch when called with original namespace=None
print("\nFETCH key when namespace=None (passed to fetch_refresh):")
fetch_pattern = full_refresh_key("jwt", "uuid1", None)
print(f"  Key: {fetch_pattern}")
print(f"  Expects: jwt__refresh_uuid1 (empty namespace)")

print("\nMismatch: SCAN found 'jwt_ns1_refresh_uuid1' but FETCH looks for 'jwt__refresh_uuid1'")
EOF

Repository: urkishan/jwt_sessions

Length of output: 151


🏁 Script executed:

python3 << 'EOF'
# The key format is: prefix_namespace_refresh_uuid
# To extract namespace, we'd need to parse it differently

key_example1 = "jwt_ns1_refresh_uuid123"
key_example2 = "jwt_ns2_refresh_uuid456"
key_example3 = "jwt__refresh_uuid789"  # empty namespace

# Current implementation (wrong approach):
def uuid_from_key_current(key):
    return key.split("_").last  # last part after splitting

# Would need something like:
# 1. Extract parts: jwt, namespace, refresh, uuid
# 2. Or store namespace as part of the hash
# 3. Or derive namespace from the pattern match

print("Current implementation extracts only UUID from the key")
print("It doesn't know which namespace each key belongs to")
print("This is why the review comment suggests deriving namespace from key")
EOF

Repository: urkishan/jwt_sessions

Length of output: 151


🏁 Script executed:

grep -n "namespace.nil?" lib/jwt_sessions/store_adapters/memory_store_adapter.rb -B2 -A5

Repository: urkishan/jwt_sessions

Length of output: 351


all_refresh_tokens(nil) may not return tokens from all namespaces

When namespace is nil, the scan pattern via refresh_key("*", nil) converts to refresh_key("*", "*"), producing pattern prefix_*_refresh_* that correctly scans keys across all namespaces. However, fetch_refresh(uuid, namespace) is then called with the original namespace parameter (nil), not the namespace extracted from each scanned key.

This causes a mismatch: keys like prefix_ns1_refresh_uuid1 are scanned, but fetch_refresh constructs the key as prefix__refresh_uuid1 (with empty namespace from nil), which doesn't exist. All fetches return {}, so all_refresh_tokens(nil) returns an empty hash instead of tokens from all namespaces. The MemoryStoreAdapter correctly handles this by explicitly iterating through all namespaces when namespace is nil.

Extract the namespace from each scanned key (parsing prefix_namespace_refresh_uuid) rather than reusing the inbound parameter, or skip entries where fetch_refresh returns {}.

🤖 Prompt for AI Agents
In lib/jwt_sessions/store_adapters/redis_store_adapter.rb around lines 70 to 75,
all_refresh_tokens(namespace) scans keys across namespaces when namespace is nil
but then calls fetch_refresh(uuid, namespace) using the original nil namespace,
causing lookups to fail; change the logic to parse each scanned key to extract
the namespace and uuid (e.g. split the key by the known prefix/segments to get
namespace and uuid) and call fetch_refresh(uuid, extracted_namespace) for each
entry, skipping entries that still return empty results; ensure the parsing
handles the expected key format and nil namespace case consistently.

Comment on lines +87 to 93
def refresh_uuid(key)
storage.get(jti_key(key))
end

def set_refresh_uuid(key, uuid, expiration)
storage.set(jti_key(key), uuid, ex: expiration)
end
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

git ls-files | grep -i redis

Repository: urkishan/jwt_sessions

Length of output: 186


🏁 Script executed:

find . -name "*redis*" -type f

Repository: urkishan/jwt_sessions

Length of output: 190


🏁 Script executed:

cat -n lib/jwt_sessions/store_adapters/redis_store_adapter.rb

Repository: urkishan/jwt_sessions

Length of output: 6857


🏁 Script executed:

rg -n "storage\.set.*ex:" lib/jwt_sessions/store_adapters/redis_store_adapter.rb

Repository: urkishan/jwt_sessions

Length of output: 123


🏁 Script executed:

rg -n "\.set\(" lib/jwt_sessions/store_adapters/redis_store_adapter.rb

Repository: urkishan/jwt_sessions

Length of output: 157


🏁 Script executed:

rg -n "ex:" lib/jwt_sessions/

Repository: urkishan/jwt_sessions

Length of output: 178


🏁 Script executed:

rg -n "set_refresh_uuid" lib/jwt_sessions/

Repository: urkishan/jwt_sessions

Length of output: 552


🏁 Script executed:

cat -n test/units/jwt_sessions/store_adapters/test_redis_store_adapter.rb | head -200

Repository: urkishan/jwt_sessions

Length of output: 3285


🏁 Script executed:

sed -n '30,50p' lib/jwt_sessions/session.rb

Repository: urkishan/jwt_sessions

Length of output: 569


🏁 Script executed:

sed -n '140,150p' lib/jwt_sessions/session.rb

Repository: urkishan/jwt_sessions

Length of output: 254


🏁 Script executed:

sed -n '75,90p' lib/jwt_sessions/store_adapters/memory_store_adapter.rb

Repository: urkishan/jwt_sessions

Length of output: 658


🏁 Script executed:

rg -n "def create_refresh_token|def login" lib/jwt_sessions/session.rb -A 5

Repository: urkishan/jwt_sessions

Length of output: 378


🏁 Script executed:

rg -n "renew_tokens\|reset_refresh_uuid" lib/jwt_sessions/ -B 2 -A 2 | head -60

Repository: urkishan/jwt_sessions

Length of output: 47


🏁 Script executed:

find . -name "*.rb" -type f | xargs grep -l "class RefreshToken"

Repository: urkishan/jwt_sessions

Length of output: 100


🏁 Script executed:

rg -n "class RefreshToken" lib/jwt_sessions/ -A 20

Repository: urkishan/jwt_sessions

Length of output: 1780


🏁 Script executed:

rg -n "reset_refresh_uuid" lib/jwt_sessions/ -B 3 -A 1

Repository: urkishan/jwt_sessions

Length of output: 673


🏁 Script executed:

rg -n "refresh_expiration" lib/jwt_sessions/ -B 2 -A 2

Repository: urkishan/jwt_sessions

Length of output: 1655


🏁 Script executed:

rg -n "def refresh_expiration" lib/jwt_sessions/

Repository: urkishan/jwt_sessions

Length of output: 47


🏁 Script executed:

cat lib/jwt_sessions.rb

Repository: urkishan/jwt_sessions

Length of output: 4404


set_refresh_uuid uses TTL semantics inconsistent with the rest of the adapter

Line 92 calls storage.set(jti_key(key), uuid, ex: expiration) where the ex: parameter expects a TTL in seconds. However, everywhere else in this adapter (persist_access, persist_refresh, update_refresh_expiry), the expiration parameter is an absolute Unix timestamp passed to expireat. Since callers always pass absolute timestamps (computed as Time.now.to_i + offset), the JTI→UUID mapping will live for decades instead of the intended expiration time.

Align with the rest of the adapter:

storage.set(jti_key(key), uuid)
storage.expireat(jti_key(key), expiration)
🤖 Prompt for AI Agents
In lib/jwt_sessions/store_adapters/redis_store_adapter.rb around lines 87 to 93,
set_refresh_uuid currently calls storage.set with ex: expiration (treating
expiration as TTL seconds) while the rest of the adapter uses absolute Unix
timestamps and expireat; change set_refresh_uuid to set the key without the ex
option and then call storage.expireat(jti_key(key), expiration) so the stored
JTI→UUID mapping uses the same absolute-expiry semantics as
persist_access/persist_refresh/update_refresh_expiry.

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.

2 participants