- What browsers are supported by MSAL.js?
- I am moving from MSAL.js 1.x to MSAL.js to 2.x. What should I know?
- Does this library work for iframed applications?
- Will MSAL 2.x support B2C?
- I don't understand the redirect flow. How does the handleRedirectPromise function work?
- How can I support authentication with personal Microsoft accounts only?
- How do I get an authorization code from the library?
- How to get single sign-on in my application with MSAL.js?
- How can my application recognize a user after sign-in? How do I correlate users between applications?
- What is the difference between sessionStorage and localStorage?
- What are the possible configuration options?
- Where is the authority string on Azure AD Portal?
- Why is fragment the only valid field for responseMode in msal-browser?
- How do I acquire an access token? How do I use it?
- How do I renew tokens with MSAL.js?
- How can I acquire tokens faster?
- I'm seeing scopes openid, profile, email, offline_access in my tokens, even though I haven't requested them. What are they?
- How long do tokens last? How long are they valid for?
- What are the differences between supported audiences and account types?
- How do I specify which B2C policy/user flow I would like to use?
- Why is getAccountByUsername returning null, even though I'm signed in?
- I logged out of my application. Why am I not asked for credentials when I try to log back in?
- Why am I not signed in when returning from an invite link?
- Why is there no access token returned from acquireTokenSilent?
- What should I do if I believe my issue is with the B2C service itself rather than with the library
Common Issues
MSAL.js has been tested with the following browsers:
IE 11, Edge, Chrome, Firefox and Safari
Keep these steps in mind when using MSAL.js with IE.
There are certain known issues and mitigations documented for Safari, IE and Edge. Please check out:
Please refer to our migration guide here.
We are currently working on support for iframed applications as well as solutions for applications affected by ITP 2.x changes. You can monitor the first of those tickets here.
MSAL.js v2 supports B2C of October 2020.
The redirect flow can be confusing, as redirecting away from the page means you are creating a whole new instance of the application when you return. This means that calling a redirect method cannot return anything. Rather, what happens is that the page is redirected away, you enter your credentials, and you are redirected back to your application with the response in the url hash.
If navigateToRequestUrl property in MSAL configuration parameters is set to true, you will be redirected again to the page you were on when you called loginRedirect, unless that page was also set as your redirectUri. On the final page your application must call handleRedirectPromise() in order to process the hash and cache tokens in local/session storage.
As this function returns a promise you can call .then and .catch, similar to loginPopup.
Please ensure handleRedirectPromise has resolved before invoking any other MSAL method. If your app was not loaded as a result of a redirect operation handleRedirectPromise will immediately return null.
Please review one of our samples (for instance) to see the redirect flow in action.
Simply set your authority in your MSAL app configuration to consumers tenant e.g. https://login.microsoftonline.com/consumers.
Currently the msal-browser package is designed for Single-Page Applications that are handling all authentication through the browser client. We have not yet optimized this to work with server-side components. As such, requests to retrieve the authorization code from the first leg of the flow can't be met currently. We are currently working on an implementation of msal that will run in node libraries, and as part of that we will explore options to make msal-browser work with server-side components.
Please read the documentation on Single Sign-On to learn about different scenarios in which MSAL.js enables single sign-on.
How can my application recognize a user after sign-in? How do I correlate users between applications?
You can use the homeAccountId property on the Account in the AuthenticationResult.
loginPopup().then((response) => {
const uniqueID = response.account.homeAccountId;
})We offer two methods of storage for Msal, localStorage and sessionStorage. Our recommendation is to use sessionStorage because it is more secure in storing tokens that are acquired by your users, but localStorage will give you Single Sign On across tabs and user sessions. We encourage you to explore the options and make the best decision for your application.
For MSAL.js 2.x, please review this document.
The authority string that you need to supplant to MSAL app configuration is not explicitly listed among the Endpoint links on Azure Portal/AzureAD/App Registration/Overview page. It is simply the domain part of a /token or /authorize endpoint, followed by the tenant name or ID e.g. https://login.microsoftonline.com/common.
The library is built to specifically use the fragment response mode. This is a security consideration as the fragment of the URL is not sent to the server and modifying/clearing the fragment does not result in a new page load. We are considering implementing support for other responseMode types in the future, specifically to use multiple libraries in the same app.
Please refer to token guide here.
MSAL.js provides the acquireTokenSilent method which handles token renewal by making silent token requests without prompting the user. The method first looks for a valid cached token in the browser storage. If it does not find one, the library makes the silent request to Azure AD and if there is an active user session (determined by a cookie set in browser on the Azure AD domain), a fresh token is returned. The library does not automatically invoke the acquireTokenSilent method. It is recommended that you call acquireTokenSilent in your app before making an API call to get the valid token.
In certain cases, the acquireTokenSilent method's attempt to get the token silently fails. Some examples of this are when there is an expired user session with Azure AD or a password change by the user, etc. which requires user interaction. When the acquireTokenSilent fails, you need to call one of the interactive acquire token methods (acquireTokenPopup or acquireTokenRedirect).
The tokens returned by Azure AD have a default lifetime of 1 hour. However, as long as the user is active on your application and a valid Azure AD session exists in the browser, the acquireTokenSilent method can be used to renew tokens. The Azure AD session is valid for 24 hours and can be extended by the user by choosing "Keep me signed in" option on the sign-in screen. For more details, read the token and session lifetimes document.
Please refer to our performance guide here
I'm seeing scopes openid, profile, email, offline_access and User.Read in my tokens, even though I haven't requested them. What are they?
The first four (openid, profile, email and offline_access) are called default scopes. They are added to Azure AD as part of Azure AD - OAuth 2.0/OpenID Connect compliance. They are not part of any particular API. You can read more about them here.
The scope User.Read, on the other hand, is an MS Graph API scope. It is also added by default to every app registration. However if your application is not calling MS Graph API, you can simply ignore it.
Token lifetimes are 1 hour and the session lifetime is 24 hours. This means that if no requests have been made in 24 hours, you will need to login again before requesting a new token.
Please see the documentation on Tenancy in Azure Active Directory
My application has multiple resources it needs to access to. How should I handle scopes for access tokens?
Please see the doc about resources and scopes here
The policy (a.k.a. user flow) can be appended to the authority url you provide as part of the PublicClientApplication configuration or as part of an individual request.
const config = {
auth: {
clientId: "your-client-id",
authority: "https://yourApp.b2clogin.com/yourApp.onmicrosoft.com/your_policy",
knownAuthorities: ["yourApp.b2clogin.com"]
}
}
const pca = new PublicClientApplication(config);
// You can also provide the authority as part of the request object
const request = {
scopes: ["openid"],
authority: "https://yourApp.b2clogin.com/yourApp.onmicrosoft.com/your_policy"
}
pca.loginRedirect(request);Note: Msal.js does not support providing the user flow as a query parameter e.g. https://yourApp.b2clogin.com/yourApp.onmicrosoft.com/?p=your_policy. Please make sure your authority is formatted as shown above.
In order to use getAccountByUsername() in B2C scenarios you must enable your idTokens to return the emails claim in your B2C tenant. MSAL will fill the username field on the AccountInfo object with the first element of the array returned on the emails claim. In most cases this array will only have one element, however, if you notice that your idTokens are returning more than one email on this claim, ensure you are calling getAccountByUsername with the first email.
To enable this claim open up your User Flow configuration in the Azure Portal. Click the User Attributes tab and make sure Email Address is checked. Then click the Application Claims tab and make sure Email Addresses is checked. You can verify that the emails claim is now being returned by acquiring an idToken and inspecting its contents.
When you log out of a B2C application by calling MSAL's logout() API, MSAL.js will first clear browser storage of your user's tokens then redirect you to the Azure B2C logout endpoint. The B2C service will then close your session but may not log you out of your federated IDP. This happens because the service does not make any assumptions about other apps you may want to log out of. What this means in practice is that when a user attempts to login again the B2C service will prompt the user to select which Social IDP they would like to sign in with. When the user makes their selection, they may be signed back in without interaction.
You can read more about this behavior here
MSAL.js will only process tokens which it originally requested. If your flow requires that you send a user a link they can use to sign up, you will need to ensure that the link points to your app, not the B2C service directly. An example flow can be seen in the working with B2C doc.
Azure AD B2C currently requires refresh tokens to be redeemed with the same scopes that were requested when the refresh token is first obtained. If your application requires different behavior, workarounds include:
Please ensure that these scopes are requested as part of the loginPopup,loginRedirect or ssoSilent call made prior to calling acquireTokenSilent. This ensures the refresh token is issued for the scopes you need.
Include the first set of scopes in loginPopup, loginRedirect or ssoSilent then make another call to acquireTokenRedirect, acquireTokenPopup or ssoSilent containing your 2nd set of scopes. Until the access tokens expire, acquireTokenSilent will return either token from the cache. Once an access token is expired, one of the interactive APIs will need to be called again. This is an example of how you can handle this scenario:
// Initial acquisition of scopes 1 and 2
await msal.loginPopup({scopes: ["scope1"]});
const account = msal.getAllAccounts()[0];
await msal.ssoSilent({
scopes: ["scope2"],
loginHint: account.username
});
// Subsequent token acquisition with fallback
msal.acquireTokenSilent({
scopes: ["scope1"],
account: account
}).then((response) => {
if (!response.accessToken) {
return msal.ssoSilent({
scopes: ["scope1"],
loginHint: account.username
});
} else {
return response;
}
});ssoSilent will not work in browsers that disable 3rd party cookies, such as Safari. If you need to support these browsers, call acquireTokenRedirect or acquireTokenPopup
In that case, please file a support ticket with the B2C team by following the instructions here: B2C support options.