-
Notifications
You must be signed in to change notification settings - Fork 100
[Feature] Add thread-safe token caching with auto-renewal for confidential clients #588
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[Feature] Add thread-safe token caching with auto-renewal for confidential clients #588
Conversation
- Add TokenCache struct with RWMutex for concurrent access - Implement automatic token renewal with configurable buffer - Add token validation and cache statistics - Support cache management operations (clear, stats) - Generate deterministic cache keys from scopes and tenant
- Add EnhancedClient struct with built-in token caching - Add EnhancedClientOptions for configurable renewal buffer - Import cache package for token management
- Add NewEnhancedClient with default 2-minute renewal buffer - Add NewEnhancedClientWithOptions for custom configuration - Integrate token cache with existing client functionality
- Add AcquireTokenByCredentialWithCaching with automatic token reuse - Add ForceRefreshToken for explicit token refresh - Add cache management methods (ClearTokenCache, IsTokenCached) - Add GetCacheStats for monitoring and debugging - Integrate with existing token acquisition flow
- Test token caching and reuse functionality - Test force refresh capability - Test cache expiry with configurable renewal buffer - Verify cache statistics and management operations
- Demonstrate automatic token caching and renewal - Show force refresh capability - Display cache statistics and management - Provide production-ready usage patterns
|
|
@microsoft-github-policy-service agree company="Sprinklr" |
|
Hi @mynameispathak , thanks for the PR. Today, MSAL Go caches tokens in memory, associated with each ConfidentialClientApplication object. What are you trying to achieve that you cannot do with MSAL Go today? Note:
|
bgavrilMS
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not consistent with other MSALs
|
Hi @mynameispathak , apologies for the delayed response — I wanted to ensure I reviewed everything thoroughly. Regarding issue #587, here are my thoughts:
Lastly, regarding the issues you linked at the bottom in #587 — #569 and #570 — please note that these are related to Managed Identity, not Confidential Client. They don't share the same implementation. |
|
Hi @4gust, Thank you for the detailed response. I appreciate you taking the time to review this thoroughly. However, I'd like to respectfully clarify a key point about consistency across MSAL implementations: MSAL.NET BehaviorAccording to Microsoft's official documentation, MSAL.NET's
Source: Microsoft Learn - MSAL.NET Best Practices The existence of the The InconsistencyThis creates a significant difference in developer experience: MSAL.NET (One call handles everything): var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
// Automatically checks cache, refreshes if neededMSAL Go (Manual two-step pattern required): result, err := client.AcquireTokenSilent(ctx, scopes)
if err != nil {
result, err = client.AcquireTokenByCredential(ctx, scopes)
}
// Developer must manually implement cache checkingMy ProposalI understand that Would you consider:
SummaryI'm not questioning that the current implementation works as designed. Rather, I'm highlighting that:
Regarding managed identity issues (#569, #570): I understand they're separate implementations. I mentioned them only as examples of where automatic caching/renewal could improve developer experience across different client types. Thank you for considering this feedback. I'm happy to discuss the design rationale further if there are specific reasons MSAL Go chose a different approach. |
|
Hey @4gust, @bgavrilMS, |
|
@mynameispathak Thank you for the response. I want to confirm that the primary requirement you are pointing is the automatic cache check within the acquire call itself. This functionality has already been added for the confidential client. You can review it here: #590. It should now work similar to .NET's implementation. Its released in version v1.6.0 If there is anything else you would like addressed, please let me know. |
|
Hi @4gust, @bgavrilMS, Thank you for confirming that v1.6.0 includes automatic cache lookup in I do want to note that I opened [PR #588] on October 7th addressing this exact issue, a week before [PR #590] was created on October 14th. While I'm glad to see this functionality is now available and that my analysis was validated, I'm disappointed that my contribution wasn't acknowledged or that I wasn't given the opportunity to collaborate on the implementation. Could you clarify the contribution process for this project? Specifically:
I'm interested in contributing further to this project, but I'd like to understand how to do so effectively. Thank you, |



Summary
This PR introduces enhanced token caching capabilities for confidential clients, providing thread-safe token storage with automatic renewal to improve performance and reduce unnecessary network requests.
Changes Made
New Features
sync.RWMutexNew Methods
NewEnhancedClient()- Creates enhanced client with default settingsNewEnhancedClientWithOptions()- Creates enhanced client with custom renewal bufferAcquireTokenByCredentialWithCaching()- Token acquisition with automatic cachingForceRefreshToken()- Force refresh and cache new tokenClearTokenCache()- Clear all cached tokensIsTokenCached()- Check if valid token exists in cacheGetCacheStats()- Get cache statisticsImplementation Details
Benefits
Clientremains unchangedUsage Example
Testing
Related Issues
Closes #587
Breaking Changes
None - this is purely additive functionality.