Authenticating with msal via browser

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

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?

Azure Active Directory
Azure Active Directory
An Azure enterprise identity service that provides single sign-on and multi-factor authentication.
12,560 questions
{count} votes

4 answers

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

    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.


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

    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!

    No comments

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

    @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  
    
    No comments

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

    Hello,

    Does anyone have a solution for this issue ?

    Thank you in advance.

    No comments