cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
47.04k stars 3.19k forks source link

Azure AD B2C Authentication not working when automated with Cypress #29576

Open drieswtrs opened 5 months ago

drieswtrs commented 5 months ago

Current behavior

Situation: Cypress 13.10.0 Application using Azure AD b2c authentication with auth code grant, for an application where the auth provider domain is a subdomain of the application domain.

E.g. executing login scenario without cy.origin(...) command:

When using cy.origin("https://login.domain.com", ...), Cypress throws error since origin can only be executed on different domain than top. --> cy.origin() requires the first argument to be a different domain than top. You passed https://login.domain.com to the origin command, while top is at https://app.domain.com

To solve this problem, we need to use two different cy.origin(...) blocks, one for the app domain interactions and one for the actual authentication.

Desired behavior

Redirects between root domain and subdomain should behave similar to real browsers. --> Allow subdomain redirects

Allow the use of the cy.origin(...) command on subdomain of the top domain. --> Configure through cy.origin(...) options { allowSubdomainOrigin: true }

Test code to reproduce

E.g. executing login scenario without cy.origin(...) command:

        cy.visit("https://app.domain.com/")

        // Select language and country in app
        ...

        // Select "Sign in" option
        cy.get('button')
             .contains("Sign in")
             .click()

        // Sign in
        cy.get('input[id="signInName"]')
            .type(username)
        cy.get('input[id="password"]')
            .type(password)
        cy.get('button[type="submit"]')
            .click()

        // Redirect to 

When using cy.origin("https://login.domain.com", ...), Cypress throws error since origin can only be executed on different domain than top.

        cy.visit("https://app.domain.com/")

        // Select language and country in app
        ...

        // Select "Sign in" option
        cy.get('button')
             .contains("Sign in")
             .click()

        // Origin used for the actual authentication
        cy.origin('https://login.domain.com', { args: { username, password } }, ({username, password}) => {
            // Sign in
            cy.get('input[id="signInName"]')
                .type(username)
            cy.get('input[id="password"]')
                .type(password)
            cy.get('button[type="submit"]')
                .click()
        })

--> cy.origin() requires the first argument to be a different domain than top. You passed https://login.domain.com to the origin command, while top is at https://app.domain.com

To solve this problem, we need to use two different cy.origin(...) blocks, one for the app domain interactions and one for the actual authentication.

        // Visit to google is needed to set the Cypress top domain to a different domain than the app domain
        cy.visit('www.google.com')

        // Root origin for application
        cy.origin('https://app.domain.com', () => {
            cy.visit("https://app.domain.com/")

            // Select language and country in app
            ...

            // Select "Sign in" option
            cy.get('button')
                .contains("Sign in")
                .click()
        })

        // Origin used for the actual authentication
        cy.origin('https://login.domain.com', { args: { username, password } }, ({username, password}) => {
            // Sign in
            cy.get('input[id="signInName"]')
                .type(username)
            cy.get('input[id="password"]')
                .type(password)
            cy.get('button[type="submit"]')
                .click()
        })

Cypress Version

13.10.0

Node version

18.17.1

Operating System

Windows 11

Debug Logs

No response

Other

No response

jennifer-shehane commented 5 months ago

You shouldn't need to use cy.origin to visit in between 2 of the same origins with a different subdomain (assuming there is not another domain redirect in between them. I don't think that is the reason you're getting a 400 here. I'd encourage you to investigate why you're getting a 400 response and not use cy.origin.

naveensivakumar013 commented 2 months ago

@drieswtrs @jennifer-shehane, I am also having the same issue. @jennifer-shehane Yes based on the scenario we may not required to use cy. origin. But nothing was found after analysing the 400 error root-cause because that is perfectly working manually. I tried the same approach as @drieswtrs mentioned and didn't get the 400 error and could log in successfully. But I ended with another issue after login. Since we visited Google initially and performed all the login steps inside thecy.origin. I cannot able to access any page elements in the feature file steps. We are using Cucumber Framework so I cannot put every step under directly on the origin block. When I attempted to execute using feature file steps I got below error,

Failed to read a named property 'document' from 'Window': Blocked a frame with origin "https://www.google.com" from accessing a cross-origin frame.

@drieswtrs Have you faced this issue or handled using something else?