Closed mderriey closed 3 years ago
I reverted back to msal@1.3.2
and @azure/msal-angular@1.0.0
, and can confirm that no additional requests are made when navigating between pages.
There are still two entries in the cache.
Entry number 1:
// Key
{
"authority": "https://login.microsoftonline.com/<aad-tenant-id>/",
"clientId": "<aad-client-id>",
"scopes": "<aad-client-id>",
"homeAccountIdentifier": "<account-identifier>"
}
// Value
{
"accessToken": "<token>", // same as idToken
"idToken": "<token>", // same as accessToken
"expiresIn": "1599554514",
"homeAccountIdentifier": "<base-64-string>"
}
Entry 2
// Key
{
"authority": "https://login.microsoftonline.com/<aad-tenant-id>/",
"clientId": "<aad-client-id>",
"scopes": "<aad-client-id>/.default",
"homeAccountIdentifier": "<account-identifier>"
}
// Value
{
"accessToken": "<token1>", // NOT the same as idToken
"idToken": "<token2>", // NOT the same as accessToken
"expiresIn": "1599554611",
"homeAccountIdentifier": "<base-64-string>"
}
Reverting to msal@1.3.2 and @azure/msal-angular@1.0.0 worked for me as well.
This is a known issue with msal@1.4.0
and will be addressed by #2206
Downgrading from 1.4 is not an option for me since I use this library to access both AAD and ADFS.. But I wired up my own token refresh, and it works well so far (built off of @scambier in https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/759)
async function getTokenInternal() {
var token
if (client.getAccount()) {
var cachedToken = await getCachedToken(300)
if (cachedToken != null) token = cachedToken
else
await client.acquireTokenSilent(request)
.then(response => {
token = response.idToken.rawIdToken
})
.catch(err => {
console.log(err);
logout()
});
} else {
await login().then(response => {
token = response
})
}
return token
}
async function getCachedToken(seconds) {
const timestamp = Math.floor((new Date()).getTime() / 1000)
let token
try {
for (const key of Object.keys(sessionStorage)) {
if (key.includes('"authority":')) {
const val = await JSON.parse(sessionStorage.getItem(key))
if (val.expiresIn > (timestamp + seconds) && val.idToken === val.accessToken)
token = val.idToken
}
}
} catch (err) {
console.dir(err)
}
return token
}
Hey folks, thanks for pushing msal@1.4.1.
I tested it and I unfortunately observe the same behaviour as @1.4.0, i.e. every route change triggers an id token refresh request to AAD.
I suspect in my case, it might be because we're using a multitenant application:
authority
set to https://login.microsoftonline.com/<tenant-id>
; buthttps://login.microsoftonline.com/common
, which is what is looked for in the cache.The call stack is:
acquireTokenSilent
;getCachedToken
: call site and function definition;getCachedIdToken
: call site and function definition;cacheStorage.getIdToken
with the authority configured at the UserAgentApplication
level: call siteSee also some logs — I was surprised to see the logs mentioned 1.4.0 but I triple checked I had 1.4.1 installed.
Because we're using @azure/msal-angular, we have no possibility to pass the correct authority into the acquireTokenSilent
call.
Happy to open a different issue if you deem it's a different one.
@mderriey Thanks for the detailed explanation, this behavior with common authorities was fixed a while back for access token lookup but it seems this was not carried over to the new id_token lookup logic. We will make sure this gets addressed in 1.4.2, apologies for the inconvenience.
This issue has not seen activity in 14 days. It will be closed in 7 days if it remains stale.
Library
msal@1.4.0
@azure/msal-browser@2.x.x
@azure/msal-angular@0.x.x
@azure/msal-angular@1.1.1
@azure/msal-angularjs@1.x.x
Framework
Angular 9
Description
The framework generates too many id token requests when switching routes. We have a relatively basic setup, with different routes that use MsalGuard to ensure that users are signed in, and every route change triggers an authorization request to AAD in an iframe to get an id token.
I followed the call stack while debugging and it goes like:
MsalGuard
callsacquireTokenSilent
using the AAD client id as the one and only scope; see code hereMsalService
delegatesacquireTokenSilent
toUserAgentApplication
; see code hereUserAgentApplication
callsRequestUtils.validateRequest
which translates the unique scope that matches the configured client id into theopenid
andprofile
scope; see UserAgentApplication call and RequestUtils.validateRequest implementationUserAgentApplication.acquireTokenSilent
, we try to get a cached token; see code heregetCachedToken
method internally callsgetAllAccessTokens
getAllAccessTokens
looks in the keys of the configured storage and tries to match three pieces of information:In our case, this method only returns one token, which doesn't have the scopes we're looking for, which as a reminder are
openid
andprofile
— more on that below.getCachedToken
, since we don't find a token with matching scopes, we returnnull
renewIdToken
which initiates an authorization request via an iframe.Our config is as follows:
At runtime, from a clean tab, the following happens:
Looking at the cache, I have two entries.
I assume one represents the id token that was acquired during the login flow. It looks like this:
The other entry in the cache, which I think represents the access token, looks like below:
I'd say the MsalService/UserAgentApplication is supposed to get the id token from the cache, but because its key doesn't have the "scopes" value in it, it's a cache miss, which means we get a new one every time.
Error Message
Security
Regression
[X] Did this behavior work before? Versions:
msal@1.3.2
@azure/msal-angular@1.0.0
MSAL Configuration
Provided above.
Reproduction steps
Expected behavior
Browsers/Environment