Reputation: 4570
I'm lookig at MSAL and I'm trying to understand what's the correct way to use it in a client app. In my case, I'd like to authenticate the user and then use the id token against a "private" web api app.
Now, I was under the impression that AcquireTokenSilentAsync would reuse an existing token from the cache (when available) without performing an extra call to the authentication endpoint if the token was still valid and the requestes scopes could be satisfied (this was my interpretation and it probably is wrong). However, this seems not to be the case. What I'm seeing with fiddler is that this method will always access the authorization endpoint.
Initially, I thought that my client service wrappers should always cal this method in order to get the id token, which would then be passed to the backend web site through the authentication bearer header. Here's an example of what I mean:
public async Task<string> GetAllWorkers() {
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await GetToken());
var request = new HttpRequestMessage(HttpMethod.Get, _url);
var resposta = await _httpClient.SendAsync(request);
var content = await resposta.Content.ReadAsStringAsync();
return content;
}
GetToken
is a method that wraps the typical code used for authenticating the user (uses a try/catch block for wrapping the AcquireTokenSilentAsync and, when that fails, redirects the user to the AcquireTokenAsync method for showing the login UI).
The question: is having this extra call before all my backend services really the way to go? Or should I cache the token and reuse it in all the internal web services call until I get a 401 (and only then should I call the GetToken method to refresh my id token?)
Editing to give more info
_clientApp = new PublicClientApplication(ClientId,
Authority,
TokenCacheHelper.GetUserCache());
TokenCacheHelper is the token cache helper that comes with most Azure AD samples. The GetToken
method which returns the authentication header is a single liner that interacts with the helper that encapsulates the _clientApp field shown above:
return (await _helper.AuthenticateUser()).IdToken
And here is the AuthenticateUser method:
public async Task<AuthenticationResult> AuthenticateUser() {
try {
return await _clientApp.AcquireTokenSilentAsync(_scopes, _clientApp.Users.FirstOrDefault());
}
catch (MsalUiRequiredException ex) {
return await RetryWithGraphicalUI();
}
}
Now, the token cache helper is being hit. What I don't understand is why the AcquireTokenSilentAsync method ends up always calling the oauth2 endpoint (https://login.microsoftonline.com/{azure ad guid}/oauth2/v2.0/token)...
Meanwhile, I've changed the code making my helper class cache the AuthenticationResult. Now, AcquireTokenSilentAsync will only be called when one of the "internal" app's web api methods return 401 in response to a call performed with the bearer authorization header.
Upvotes: 0
Views: 1231
Reputation: 4570
In the end, I've went along with caching the AuthenticationResult and it's ID Token. This seems to be the best option since it saves me a remote call. I'll only try to call AcquireTokenSilentAsync
again when the web service returns 401.
Upvotes: 1