I've been having the same issue. There seems to be a lot of samples for working with ADAL (example), but after a lot of trial and error, I've got close with MSAL:
const tenant = 'https://login.microsoftonline.com/{my_tenant_id}/';
const tenantUrl = `${tenant}oauth2/token`;
const clientId = '{my_app_id}';
const clientSecret = '{my_secret}';
const azureResource = 'api://{my_app_id}';
export function login() {
cy.request({
method: 'POST',
url: tenantUrl,
form: true,
body: {
grant_type: 'client_credentials',
client_id: clientId,
client_secret: clientSecret,
resource: azureResource
}
}).then(response => {
const Token = response.body.access_token;
window.localStorage.setItem(`msal.idtoken`, Token);
window.localStorage.setItem(`msal.client.info`, `{my_hard_coded_value}`);
});
Cypress.Commands.add('login', login);
Unfortunately I'm still unfamilar with Azure AD and Cypress, but this seems to get Cypress past the login stage.
The values for my_tenant_id, my_app_id and my_secret are readily available in the Azure Portal.
The setting I'm unsure of is msal.client. info. I noticed that in a normal browser session, local storage has quite a few msal settings, but only msal.idtoken and msal.client. info are strictly required. The idtoken value is returned in response.body.access_token, so it's easily added. However, msal.client. info seems to return the same value each time. I'm not sure if that's always the case, but for now, I've simply added the hard-coded value from a browser session into the above code. Seems to work for me, but I'd like to understand it a little better.