Problem with CSRF protected Login in Cypress

Viewed 2754

I try to test a PHP Symfony application via Cypress.io but got problems with a custom login command which uses CSRF protection.

My command looks like this:

Cypress.Commands.add('login', () => {
    cy.request('/login')
        .its('body')
        .then((body) => {
            const $html = Cypress.$(body);
            const csrf = $html.find('input[name=_csrf_token]').val();

            cy.request({
                method: 'POST',
                url: '/login',
                failOnStatusCode: false,
                form: true,
                body: {
                    username: 'user',
                    password: 'password',
                    _csrf_token: csrf,
                },
            })
        });
});

This is the test spec:

describe('Masterdata Test', () => {
    beforeEach(() => {
        cy.login();
        cy.visit('/masterdata/autoselector');
    });

    it('highlights the correct register', () => {
        cy.get('.registerTab.bg-white').contains('Masterdata');
    });
});

When I run the tests it seems that the login somehow works (it returns a 200 status code) but when it visits the url which should be checked it redirects to login again. (See picture below)

enter image description here

I already checked that the CSRF token is correct and I also removed the whole CSRF protection from the login and only used the second cy.request call in my login command and it worked just fine.

Can someone help me out with this?

3 Answers

The below code worked for me,

PS: Only for UI based login.

before(() => {
    cy.visit("/");
    cy.get(/*<get the webelement for csrf token>*/).invoke('attr', 'value').then(($value) => {
        cy.setCookie('csrftoken', $value);
    });
});

beforeEach(() => {
    Cypress.Cookies.preserveOnce('csrftoken');
});

I had exactly the same problem: The form would just reload without any error.

Turns out for me this happened because php sessions in Symfony where not working with APP_ENV=test and therefore the csrf token would change on every request ;-) I had to switch to dev or prod and then it worked just fine.

I discovered this by testing if the csfr token would be the same between reloads:

describe('Check csrf', () => {
    it('Grabs Token and reloads', () => {
        // get csrf token and output to command log
        cy.request('/login')
        .its('body')
        .then((body) => {
        const $html = Cypress.$(body)
        const csrf = $html.find('input[name=_csrf_token]').val()
        cy.log(csrf)
        })

        // do the same again
        cy.request('/login')
        .its('body')
        .then((body) => {
        const $html = Cypress.$(body)
        const csrf = $html.find('input[name=_csrf_token]').val()
        cy.log(csrf)
        })
    })
})
Related