We are using Configurable token lifetimes in Azure Active Directory to change the max session age for multi-factor scenarios. While I've updated the policy with the command below, and confirmed that the access token lifetime changed from the default 60 minutes to 30 minutes, it did not change to 10 minutes as the policy indicates it should below. I've also confirmed it is the default org policy.
Set-AzureADPolicy -Id <OBJECT ID> -DisplayName "OrganizationDefaultPolicyUpdatedScenario" -Definition #('{"TokenLifetimePolicy":{"Version":1,"AccessTokenLifetime":"00:30:00","MaxAgeMultiFactor":"00:11:00","MaxAgeSessionMultiFactor":"00:10:00"}}')
I've checked the JWT token and confirmed exp is 30 minutes, so AccessTokenLifetime is implemented, but I'm using Outlook to test and confirmed MFA. The amr claim is "pwd,mfa".
Indirectly I think the MaxAgeMultiFactor timeout is working, but the session timeout is longer so it is hard to tell.
Why isn't MaxAgeSessionMultiFactor at 10 minutes (the minimum) working?
What am I doing wrong?
Complete policy:
class Policy
{
Id = 2a094bfe-d74e-4d55-906f-7cef8e54746b
OdataType =
AlternativeIdentifier =
Definition =
[
{
"TokenLifetimePolicy":
{
"Version":1,
"AccessTokenLifetime":"00:30:00",
"MaxAgeMultiFactor":"00:11:00",
"MaxAgeSessionMultiFactor":"00:10:00"
}
}
]
DisplayName = OrganizationDefaultPolicyUpdatedScenario
IsOrganizationDefault = True
KeyCredentials =
[
]
Type = TokenLifetimePolicy
}
Generally once access token is obtained, Azure AD will only check for the refresh token at the time of renewal. If the refresh token is also expired, Azure AD will then force the user for a fresh auth and check if MFA is required. If MFA is required, Azure AD will look to see if MFA cookie exists, MFA cookie is valid or not etc.
I see that you have only modified the access token lifetime and MFA lifetimes. So unless your MaxAgeSessionSingleFactor lifetime (Refresh Token) is less than MaxAgeSessionMultiFactor user will not be affected or prompted for MFA. Also single-factor authentication is considered less secure than multi-factor authentication, we recommend that you set MaxAgeSessionSingleFactor property to a value that is equal to or lesser than the Multi-Factor Refresh Token Max Age property(MaxAgeSessionMultiFactor).
With that being said, this feature is being deprecated as described in the article you are following. So we do not recommend using this feature in new environments.
"After hearing from customers during the preview, we're planning to replace this functionality with a new feature in Azure Active Directory Conditional Access. Once the new feature is complete, this functionality will eventually be deprecated after a notification period. If you use the Configurable Token Lifetime policy, be prepared to switch to the new Conditional Access feature once it's available." from the article.
Related
We are using azure/msal-angular v2.3 with ADB2C Custom policies having MFA enabled with either Phone or Email method.
Many LIVE users are reporting issues while logging in.
At times they need to do MFA twice (at times thrice) to get into the application.
After digging into the audit logs from b2c and HAR file from the customer we observed below error is being raised in User Journey.
{
"error": "invalid_grant",
"error_description": "AADB2C90080: The provided grant has expired. Please re-authenticate and try again. Current time: 1676016884, Grant issued time: 1675941825, Grant expiration time: 1675951412\r\nCorrelation ID: 6052f247\r\nTimestamp: 2023-02-10 08:14:44Z\r\n"
}
As per my understanding msal 2.x automatically handles the token refresh and we don’t need to implement any code for acquiring tokens silently. Don't know why it is expring.
Is it affecting if user keeps the screen idle for long?
Any help to resolve this is appreciated , Thanks in advance.
You are correct that msal 2.x automatically takes care to refresh token. But in few cases when user is inactive for long time or when access token expiry is less than the refresh token default time set.
In that case, acquireTokenSilent() method can be used to obtain a new token.To obtain a new access token silently, call the acquireTokenSilent() method of the MsalService with the desired scopes.
Code:
getToken() {
this.authService.acquireTokenSilent({
scopes: ['<your-scope>'],
}).then((accessToken: string) => {
// Use the access token // console.log('New token:', token);
}).catch((error: any) => {
console.log(error);
});
Check expiration times of the access and refresh tokens, and refresh interval set. Adjust these settings using accessTokenExpirationOffsetInSeconds property to tell number of seconds/minutes before which refresh token has to be set.
this.authService.init({
auth: {
clientId: '<your-client-id>',
authority: '<your-b2c-tenant>.b2clogin.com/<b2c-tenant>.onmicrosoft.com/B2C_1_<policy-name>',
redirectUri: '<your-redirect-uri>',
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: true,
accessTokenExpirationOffsetInSeconds: 300,
},
});
}
In this MSAL will try to refresh the access token within 5 minutes ~ 300 seconds before it expires.
This error or failure can happen if the user takes too long to complete the MFA flow.
For that ,In custom policy set the timeout for mutifactor authentication to 5 minutes to give minimum time for user to authenticate.
<OrchestrationStep Order="2" Type="MultiFactorAuthentication">
<MultiFactorAuthentication>
<AuthenticationMethods>
<AuthenticationMethod ReferenceId="phoneFactor" />
<AuthenticationMethod ReferenceId="emailFactor" />
</AuthenticationMethods>
<FailureModes>Deny</FailureModes>
<Default>false</Default>
<SendErrorCodesToResponse>false</SendErrorCodesToResponse>
<Enrollment>Conditional</Enrollment>
<phoneFactor-Timeout>300</phoneFactor-Timeout>
<emailFactor-Timeout>300</emailFactor-Timeout>
</MultiFactorAuthentication>
By theses token refresh behavior can be contolled.
Reference :
Configure authentication in a sample single-page application by using Azure Active Directory B2C | Microsoft Learn
Configure session behavior - Azure Active Directory B2C | Microsoft Learn
I am adapting the project sample provided by Microsoft for Multi-tenant Azure AD apps.
I am extending SurveyAuthenticationEvents.TokenValidated() so that in the sign up logic, I hit up Microsoft Graph to get the tenant display name so we can store something a little more meaningful than just a GUID to identify the new tenant.
Something like this:
Organization? org = default;
var tokenAcquisition = context.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>();
var auth = await tokenAcquisition.GetAuthenticationResultForUserAsync(new string[] { "User.Read" }, tenantId: azureTenantId, user: context.Principal); // "User.Read", "Organization.Read.All"
var graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
(requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", auth.AccessToken); // context.SecurityToken.RawData);
return Task.CompletedTask;
}));
var results = await graphClient.Organization.Request().Select(x =>x.DisplayName).GetAsync();
org = results.FirstOrDefault();
The third line is failing with the exception:
Microsoft.Identity.Client.MsalUiRequiredException: AADSTS65001: The user or administrator has not consented to use the application with ID 'xxxxxx' named 'xxxxx'. Send an interactive authorization request for this user and resource.
Please note that this is IMMEDIATELY after the tenant administrator has just consented.
However, the error seems to be intermittent. In fact if I debug and break on the problematic line, wait a couple of seconds and then let it run it works fine. It is as if Azure AD needs a second or two after the consent to properly update the service principals and consent status for the new tenant, before it will issue an access token for a downstream API.
Am I missing something here or do I just add some retries and work around the issue?
If an admin consent is already believed to be done , maybe all of the required permissions listed in the sign-in request were not consented to
or
the wrong application was used based on the App-Id}from the table above.
In that case try to add this as an authorized client application
Once the application has been consented ,please make sure the prompt parameter is not being specified. If prompt parameter is still passed after consent this error might occur
For workaround delete the package , permissions and again add it so your permission request gets created again.Also check if you need additional permissions like openid , profile ,offline_access for refresh token in your case.
Please check other possible causes here
Troubleshooting consent in Azure AD | Azure Active Directory Developer Support Team (aaddevsup.xyz) which can guide to troubleshoot
Reference:
Unexpected consent prompt when signing in to an application - Microsoft Entra | Microsoft Docs
Based on some feedback on github (https://github.com/mspnp/multitenant-saas-guidance/issues/127) it appears that the issue is indeed due to timing issues with AzureAD infrastructure, possibly related to caching.
Would be fantastic if this was documented!
I have now introduced some retry logic that simply waits a few seconds and retries the same request (up to 5 times) and the sign up logic now works as expected.
Thanks to #dmcsweeney on github
Our SPA uses Azure B2C and MSAL (React) for user authentication. There are other requirements so we use custom policies instead of predefined user flows. But I struggle to implement Keep Me Signed In (KMSI) feature following these instructions.
I used custom policies from the starter pack: Phone_Email_Base.xml and SignUpOrSignInWithPhoneOrEmail.xml
Added <Item Key="setting.enableRememberMe">True</Item> entry to <TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Phone-Email">
Updated relying party policy file with this:
<UserJourneyBehaviors>
<SingleSignOn Scope="Tenant" KeepAliveInDays="30" />
<SessionExpiryType>Absolute</SessionExpiryType>
<SessionExpiryInSeconds>1200</SessionExpiryInSeconds>
<ScriptExecution>Allow</ScriptExecution>
</UserJourneyBehaviors>
Set up MSAL instance in my index.tsx following this. Lib versions: "#azure/msal-browser": "^2.14.2", "#azure/msal-react": "^1.0.0"
Tried to obtain access token:
msalInstance
.acquireTokenSilent(accessTokenRequest)
.then((response) => {
// use response.accessToken here
...
})
.catch((e) => {
console.error(e);
if (e instanceof InteractionRequiredAuthError) {
instance.acquireTokenRedirect(accessTokenRequest);
}
});
The problem is MSAL cannot retrieve access token silently after 24 hours from user logged in (i.e. once refresh token is expired) and requires user to re-login.
To make sure that my application code is Ok, I tried to use predefined user flow (combined B2C_1_SignUpSignIn) with KMSI feature enabled. And in this case, my application is able obtain access token silently after 24 hours. So KMSI works perfectly with user flow, but doesn't with custom policy.
Crawled through docs and examples for days, but still can't find any clues what else needs to be done here. Any help would be appreciated.
When acquireTokenSilent() fails, MSAL will call ssoSilent(). This will launch a hidden iframe to try to get a token using cookie based SSO.
When this fails, a final error will come back. You must catch this error and call acquireTokenRedirect(). Now if your session setup for your technical profiles is setup properly, and a valid session cookie exists, you’ll get SSO.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-reference-sso
If you are actually seeing a prompt for user input, your session setup is not correct for that particular techical profile. This is the real reason why ssoSilent() failed.
Your problem is not KMSI. To prove it, remove KMSI config, sign in to your app, remove the MSAL objects from the LocalStorage, force a token renewal. You’ll reproduce the issue you described, even without KMSI, and just after a few minutes of logging in.
Well, eventually it turned out that this solution actually works. Still not sure why it failed after the first 24 hours after the custom policy was applied. So I was forced to re-login after the first 24 hours but when the other 24 hours passed, my application was able to get a new access token without providing credentials by the user.
We have tried extending the session token time of an openid application on-boarded in Azure AD by configuring Sign-in frequency in Azure AD Condition Access Policy as suggested in the below MS document -
https://learn.microsoft.com/en-us/azure/active-directory/conditional-access/howto-conditional-access-session-lifetime
But it doesn't prompt for re-authentication after the configured sign-in frequency time period expires.
We have on-boarded ClickHelp app & set the sign-in frequency for 1 hour.
Need help with the configuration in Azure AD to extend the oAuth app session token time by 8hrs (application session should get expire after 8hrs & prompt to re-authenticate with Azure AD)
Also, wanted to know if conditional access policy only works with Microsoft apps?
Because when I configured policy for all cloud apps with sign-in-frequency set to 1hr, and hit the URL "https://endpoint.microsoft.com" in browser. I received the following error message on refreshing the URL after 1 hr -
Conditional access policy failure
{
"sessionId": "1026a56be9a04d77xxxxxx",
"missingClaims": "{"access_token":{"capolids":{"essential":true,"values":["83b40f65-1d01-45cc-xxxx-xxxxxxxx"]}}}",
"resourceName": "graph",
"errorMessage": "AADSTS70043: The refresh token has expired or is invalid due to sign-in frequency checks by conditional access. The token was issued on 2020-09-15T11:26:21.5620000Z and the maximum allowed lifetime for this request is 3600.\r\nTrace ID: 2933c79c-e69b-xxxx-xxxx-xxxxxxxxx\r\nCorrelation ID: aab286b8-ea79-xxxx-xxxx-xxxxxxxxx\r\nTimestamp: 2020-09-15 12:50:22Z"
}
I have created access token using AcquireToken method (with default 1 hour expiration) and tried to login using below command
Add-AzureRmAccount -AccessToken "string" -AccountId "string"
It produces subscription details as expected by successful login.
After this i tried to update policy as below:
Set-AzureADPolicy -ObjectId <ObjectID FROM GET COMMAND> -DisplayName TenantDefaultPolicyUpdatedScenario -Definition #("{`"TokenLifetimePolicy`":{`"Version`":1,`"MaxAgeSingleFactor`":`"2.00:00:00`"}}")
But still token got expired in 1 hour.
Did i missed anything ?
what is the exact procedure and order of updating lifetime of token ?a
after setting policy how to ensure token life time ?
Thanks in advance.
According to this article, you should set AccessTokenLifetime property. Please try to use the following command.
Set-AzureADPolicy -Id <ObjectId FROM GET COMMAND> -DisplayName "OrganizationDefaultPolicyUpdatedScenario" -Definition #('{"TokenLifetimePolicy":{"Version":1,"AccessTokenLifetime":"1.00:00:00"}}')
The following is the snippet from the document.
Access Token Lifetime
String: AccessTokenLifetime
Affects: Access tokens, ID tokens
Summary: This policy controls how long access and ID tokens for this resource are considered valid. Reducing the Access Token Lifetime property mitigates the risk of an access token or ID token being used by a malicious actor for an extended period of time. (These tokens cannot be revoked.) The trade-off is that performance is adversely affected, because the tokens have to be replaced more often.
The MaxAgeSingleFactor property affects Refresh tokens.
Single-Factor Refresh Token Max Age
String: MaxAgeSingleFactor
Affects: Refresh tokens
Summary: This policy controls how long a user can use a refresh token to get a new access/refresh token pair after they last authenticated successfully by using only a single factor. After a user authenticates and receives a new refresh token, the user can use the refresh token flow for the specified period of time. (This is true as long as the current refresh token is not revoked, and it is not left unused for longer than the inactive time.) At that point, the user is forced to reauthenticate to receive a new refresh token.
Reducing the max age forces users to authenticate more often. Because single-factor authentication is considered less secure than multi-factor authentication, we recommend that you set this property to a value that is equal to or lesser than the Multi-Factor Refresh Token Max Age property.
Note: Access token without any expiry is a major security risk and it is not allowed in the Azure.
Default expiration of access token is 1 hour, minimum is 10 minutes, and the maximum is 1 day.
For more details, refer “Configurable token lifetimes in Azure Active Directory (Public Preview)”.