The `acquireTokenSilent` method is not performant when fetching token result from cache
Describe the bug
The acquireTokenSilent method, used to fetch access tokens (including the ability to refresh tokens when needed) from the MSAL SDK is not performant enough for it's use case.
In our practical use of the MSAL library, we use an OkHttp Interceptor to append tokens to each request. These tokens are pulled from MSAL using acquireTokenSilent. Based on the documentation, this should mean on most requests that the access tokens are pulled from a cache and returned, except in the case where there is no valid access token. This works, but the time to fetch a token from the MSAL using this method is not performant - on the order of hundreds of milliseconds. When caching the access token locally instead we're able to fetch new tokens in less than 100ms.
Smartphone
Observed on multiple combinations of Android devices, operating systems, and browsers.
com.microsoft.identity.client:msal version 4.0.1.
Stacktrace N/A
To Reproduce Steps to reproduce the behavior:
- Follow vanilla setup for MSAL Android project
- Use
acquireTokenSilentto fetch tokens on every network call - Make network calls as normal, and log the duration of each
acquireTokenSilentcall
Expected behavior
When access token is valid, calls to acquireTokenSilent should return tokens almost instantaneously.
Actual Behavior
When access token is valid, calls to acquireTokenSilent are returning tokens in between 100-1000ms.
Screenshots Timing the time it takes to get a token from MSAL vs. pulling it from our local cache.
| Using MSAL | Local Cache |
|---|---|
Additional context Related SO Post summarizing the same issue.
Hi @aj-kueterman, Thanks for your patience. Can you please provide some more details?
- Are you performing high number of transactions on your cache?
- Device details?
- Can you please try using the latest version of the MSAL and check if this solves your problem?
Thank you for your response @negoe,
- Yes, we use
acquireTokenSilentto fetch an access token on every request. Our app does heavily rely on network calls and we often make them in bunches (like during app startup). - Happening across devices & emulators, but I'm testing on a Google Pixel 4a on Android 13.
- Yes, I'll run a test on the latest version and see if I see any performance improvements and report back.
This is something we have had for a long time too. We also made a local cache as a work around. The only 'isuse' I can think of that could cause it is that we currently call quite a few different backend systems that all use a different token scope (And that MSAL cant handle multiple tokens well). Im curious if that (multiple scopes) is something you also have @aj-kueterman ?
Following up @negoe - no noticeable improvement from updating to the latest MSAL version. One thing I did want to specify is that my testing was done on a debug build. Using release did speed things up significantly, but still not close to the performance of a local cache.
@MartijnvAdrichem we do have multiple scopes, but only one that is used most often. Couldn't rule it out as a factor for sure.
@aj-kueterman We have created a work item for this on our backlog. Our eng team will take a look into this. Thanks for your patience.
Hi @aj-kueterman
May I ask if you have Microsoft Authenticator, Intune Company Portal or Link To Windows installed on your device by any chance?
(note: Link To Windows is preinstalled on Samsung device.)
--
If so, those apps ship with an "authentication broker", and MSAL would prefer asking the broker to acquire token (as opposed to making the request by itself)
This means MSAL would need to make an IPC call, so it would occur "some" overhead cost.
Could you please provide the non-debug number on your end? (and preferably, logs from those 3 apps above)
Thanks!
@rpdome interesting. No, none of those apps. Pixel 4a pretty stock setup, so no logs to share from those apps listed. When you say non-debug number do you just mean the timing difference in release builds?
@rpdome interesting. No, none of those apps. Pixel 4a pretty stock setup, so no logs to share from those apps listed. When you say non-debug number do you just mean the timing difference in release builds?
I was referring to the benchmark numbers you mentioned here
One thing I did want to specify is that my testing was done on a debug build. Using release did speed things up significantly, but still not close to the performance of a local cache.
We observed the same when implementing MSAL back then, and have added an internal cache with a simple hashmap (due to using multiple accounts, otherwise you can probably just store it directly). Each entry has the accesstoken together with the expiresOn date, on retrieval we check if currentTimeMillis < expiresOn.getTime and only call acquireTokenSilentAsync otherwise.
Hey @rpdome we ended up doing something similar to what @slowcar had said and implemented a cache for tokens to improve performance. We haven't been able to generate great benchmark numbers for prod, and since moving to the cache we haven't had any issues, so for now it isn't affecting us. I think this may still be an issue for apps who use the MSAL directly to fetch access tokens on each request, and who make a large amount of concurrent network calls, but not able to really give more input at this time.
Appreciate the help.