Authenticating with msal via browser

Matt Strenz 1 Reputation point
2020-09-01T13:47:11.307+00:00

I'm looking to allow a UI test to bypass login via a token I'm getting from a REST request to login.microsoft.com. I have the response coming back with a valid token but am unable to populate the browser so my "user" is logged in on page load. I'm currently leveraging Cypress to validate the application and am using the below method to get my token and populate local storage and a cookie.

Cypress.Commands.add("login", () => { cy.request({ method: "POST", url: `https://login.microsoftonline.com/${Cypress.config( "tenantId" )}/oauth2/token`, form: true, body: { grant_type: "client_credentials", client_id: Cypress.config("clientId"), client_secret: Cypress.config("clientSecret"), resource: Cypress.config("clientId"), }, }).then((response) => { cy.log("RESPONSE: " + JSON.stringify(response.body)) const Token = response.body.access_token Cypress.config("Token", Token) localStorage.setItem(`{ "authority":"https://login.microsoftonline.com/${Cypress.config("tenantId")}/", "clientId": "${Cypress.config("clientId")}"}`, `{"accessToken":"${Token}","idToken":"${Token}", "expiresIn": "${response.body.expires_on}"}`) localStorage.setItem(`msal.${Cypress.config("clientId")}.idtoken`,`${Token}`) cy.setCookie(`msal.${Cypress.config("clientId")}.idtoken`,`${Token}`); }); });

Does anybody know what the browser needs to consider a user authenticated?

Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
21,799 questions
{count} votes

4 answers

Sort by: Most helpful
  1. Michael McMullin 6 Reputation points
    2020-09-26T13:47:01.533+00:00

    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.

    1 person found this answer helpful.

  2. Kimberly Ly 1 Reputation point
    2020-10-15T18:30:38.113+00:00

    Hi @Michael McMullin ,

    I want to thank you for all of the groundwork you've done to figure out which variables to set when working with MSAL! I think I can help with figuring out where clientInfo comes from. It looks like it is generated from the clientId, which explains why it is always the same value. See source here: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/70b87bcd27bfe67789c92b9bc046b45733f490ed/lib/msal-core/src/ClientInfo.ts

    I was able to use your code and just added import * as MSAL from "@azure/msal-browser" and window.localStorage.setItem(``msal.client.info``, MSAL.clientInfo);

    Worked like a charm for me!

    0 comments No comments

  3. Vaibhav Sawant 1 Reputation point
    2021-05-27T06:07:54.543+00:00

    @Kimberly Ly While setting msal.client.info in local storage, getting an error "Invalid base64 string" and it's not login user to web application. Tried to add MSAL.clientInfo by importing @azure/msal-browser. But, no luck. Can you please guide, what's going wrong here.

    import * as MSAL from "@azure/msal-browser"  
      
    Cypress.Commands.add("login", () => {  
        cy.request({  
          method: "POST",  
          url: `https://login.microsoftonline.com/${Cypress.config("tenantId")}/oauth2/token`,  
          form: true,  
          body: {  
            grant_type: "client_credentials",  
            client_id: Cypress.config("clientId"),  
            client_secret: Cypress.config("clientSecret"),  
            resource: Cypress.config("resource")  
          },  
        }).then(response => {  
          const MSALToken = response.body.access_token;  
          const expiresOn = response.body.expires_on;  
          console.log("Body: " + JSON.stringify(response.body));  
          window.localStorage.setItem("msal.token.keys", `${Cypress.config("clientId")}|`);  
          window.localStorage.setItem(`msal.access.token.key${Cypress.config("clientId")}`, MSALToken);  
          window.localStorage.setItem(`msal.expiration.key${Cypress.config("clientId")}`, expiresOn);  
          window.localStorage.setItem("msal.idtoken", MSALToken);  
          window.localStorage.setItem(`msal.client.info`, MSAL.clientInfo);  
        });  
      });  
    

    Response Received:

    {  
      "token_type": "Bearer",  
      "expires_in": "3599",  
      "ext_expires_in": "3599",  
      "expires_on": "1622095375",  
      "not_before": "1622091475",  
      "resource": "00000002-0000-0000-c000-000000000000",  
      "access_token": "eyJ0eXAiOiJKV1QiLCJh....BEFg"  
    }  
    

    Getting Error "Invalid base64 string" while setting

    window.localStorage.setItem(`msal.client.info`, MSAL.clientInfo);  
      
      
    Unhandled Promise rejection: The client info could not be parsed/decoded correctly. Please review the trace to determine the root cause. Failed with error: Error: Invalid base64 string ; Zone: <root> ; Task: Promise.then ; Value: ClientAuthError: The client info could not be parsed/decoded correctly. Please review the trace to determine the root cause. Failed with error: Error: Invalid base64 string  
        at e [as constructor] (VM19 main-es2015.5d1f7b11d6a7d9a05ff5.js:1)  
        at new e (VM19 main-es2015.5d1f7b11d6a7d9a05ff5.js:1)  
        at Function.e.createClientInfoDecodingError (VM19 main-es2015.5d1f7b11d6a7d9a05ff5.js:1)  
        at new t (VM19 main-es2015.5d1f7b11d6a7d9a05ff5.js:1)  
        at t.getAccount (VM19 main-es2015.5d1f7b11d6a7d9a05ff5.js:1)  
        at t.checkAccount (VM19 main-es2015.5d1f7b11d6a7d9a05ff5.js:1)  
        at new t (VM19 main-es2015.5d1f7b11d6a7d9a05ff5.js:1)  
        at Object.FG+x.t.ɵfac [as factory] (VM19 main-es2015.5d1f7b11d6a7d9a05ff5.js:1)  
        at Nr.hydrate (VM19 main-es2015.5d1f7b11d6a7d9a05ff5.js:1)  
        at Nr.get (VM19 main-es2015.5d1f7b11d6a7d9a05ff5.js:1) ClientAuthError: The client info could not be parsed/decoded correctly. Please review the trace to determine the root cause. Failed with error: Error: Invalid base64 string  
    
    0 comments No comments

  4. AlexandreQ 1 Reputation point
    2022-03-15T08:33:42.33+00:00

    Hello,

    Does anyone have a solution for this issue ?

    Thank you in advance.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.