Align Android session token fetching with edge minter behavior - #827
Align Android session token fetching with edge minter behavior#827swolfand wants to merge 1 commit into
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
| return if (jwt == null || tokenSessionId == null) { | ||
| true | ||
| } else { |
There was a problem hiding this comment.
🟡 Medium session/TokenFreshness.kt:45
When the JWT cannot be decoded or has no sid claim, matches returns true, so the token is treated as belonging to any session/organization. fetchToken then hydrates that session's cache with this token, causing a token lacking session identity claims to be cached and served under an unrelated session/organization instead of forcing a fresh fetch. Missing identity/context claims should fail the match rather than return true.
| return if (jwt == null || tokenSessionId == null) { | |
| true | |
| } else { | |
| return if (jwt == null || tokenSessionId == null) { | |
| false | |
| } else { |
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @source/api/src/main/kotlin/com/clerk/api/session/TokenFreshness.kt around lines 45-47:
When the JWT cannot be decoded or has no `sid` claim, `matches` returns `true`, so the token is treated as belonging to any session/organization. `fetchToken` then hydrates that session's cache with this token, causing a token lacking session identity claims to be cached and served under an unrelated session/organization instead of forcing a fresh fetch. Missing identity/context claims should fail the match rather than return `true`.
| SessionTokensCache.storeIfFresher(cacheKey, tokensRequest.value) | ||
| tokensRequest.value |
There was a problem hiding this comment.
🟠 High session/SessionTokenFetcher.kt:195
fetchToken stores the response via SessionTokensCache.storeIfFresher(...) but then returns tokensRequest.value instead of the canonicalToken that call returns. When two skipCache requests complete out of order, the late, stale response is correctly prevented from replacing the cache, but that stale response's caller still receives the stale JWT rather than the fresher canonical token — defeating the freshness guarantee for the immediate result. Consider returning the StoreResult.canonicalToken instead of the raw response.
| SessionTokensCache.storeIfFresher(cacheKey, tokensRequest.value) | |
| tokensRequest.value | |
| SessionTokensCache.storeIfFresher(cacheKey, tokensRequest.value).canonicalToken |
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @source/api/src/main/kotlin/com/clerk/api/session/SessionTokenFetcher.kt around lines 195-196:
`fetchToken` stores the response via `SessionTokensCache.storeIfFresher(...)` but then returns `tokensRequest.value` instead of the `canonicalToken` that call returns. When two `skipCache` requests complete out of order, the late, stale response is correctly prevented from replacing the cache, but that stale response's caller still receives the stale JWT rather than the fresher canonical token — defeating the freshness guarantee for the immediate result. Consider returning the `StoreResult.canonicalToken` instead of the raw response.
| /** | ||
| * Releases deduplicated waiters and removes requests registered by the previous Clerk runtime. | ||
| */ | ||
| internal fun reset() { |
There was a problem hiding this comment.
🟠 High session/SessionTokenFetcher.kt:57
reset() cancels the waiter Deferreds but not the in-flight fetchToken coroutine, so an ongoing token request can keep running after reset, write its JWT into the shared SessionTokensCache, and return a token from the old configuration to the caller. This stale credential can contaminate the new runtime. Consider cancelling or fencing the actual fetch work so an in-flight request cannot store results after reset.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @source/api/src/main/kotlin/com/clerk/api/session/SessionTokenFetcher.kt around line 57:
`reset()` cancels the waiter `Deferred`s but not the in-flight `fetchToken` coroutine, so an ongoing token request can keep running after reset, write its JWT into the shared `SessionTokensCache`, and return a token from the old configuration to the caller. This stale credential can contaminate the new runtime. Consider cancelling or fencing the actual fetch work so an in-flight request cannot store results after reset.
Summary
session_minterenvironment flag and send organization, previous-token, and force-origin parameters for default token requestsWhy
Android did not yet implement the session-minter request and freshness behavior used by clerk-js and the corresponding iOS implementation. A late stale response could overwrite a newer canonical session token, and forced refreshes were deduplicated even though each request must reach the token endpoint.
This aligns Android with the new behavior tracked in MOBILE-598 and prevents concurrent token refreshes from rolling back the cache.
Validation
./gradlew :source:api:testDebugUnitTest./gradlew :source:api:spotlessCheck./gradlew :source:api:detekt./gradlew :source:api:lintDebuggit diff --checkRelated iOS implementation: clerk/clerk-ios#534
Note
Align Android session token fetching with edge minter behavior
sessionMinterflag toAuthConfigdecoded from the environment response, which gates new minter-specific behavior in token fetching.SessionTokenFetcherto use a singleton (shared), deduplicate in-flight requests by cache key (template or active organization), and skip deduplication whenskipCacheis true.organization_idtoSessionApi.tokens; whensessionMinteris enabled, also sends the previous token and setsforce_origin=trueon forced refreshes.TokenFreshnessto compare JWT metadata (oiat,iat, org/session ID) so out-of-order responses never overwrite a fresher cached token.SessionTokensCache.storeIfFresherandhydratefor atomic, freshness-gated cache writes.reset()onSessionTokenFetcher.sharedis called during client/session clear and configuration reset to cancel in-flight tasks.🖇️ Linked Issues
Resolves MOBILE-598, which tracks aligning Android session token fetching to the equivalent changes made in clerk-js and clerk-ios.
📊 Macroscope summarized 6342742. 8 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted
🗂️ Filtered Issues
No issues evaluated.