cypress-io / cypress

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

Redirect request from external origin doesn't apply the base domain cookies #29719

Open jraoult opened 2 months ago

jraoult commented 2 months ago

Current behavior

It seems like Cypress is unable to re apply cookies set for the base domain after redirect from an different origin.

I found that while testing a typical OAuth authorization code flow. It requires at some point for the server to store a challenge (aka code) in session to then use it to verify the params when the identity provider calls back the server. In my case, the session is a encrypted cookie and while it works while manually testing I can not get this test to pass with Cypress.

Desired behavior

When the external domain wrapped in cy.origin redirects to the base domain, the request should contain the cookies for the base domain.

Test code to reproduce

it.only("can sign in with SSO", () => {
  cy.visit("/login?sso");

  const username = () => $t("username-input");
  const submit = () => $t("sign-in-button");

  username().find("input").type("{selectall}me@example.com");

  // this triggers a session creation (set-cookie) and redirects to onelogin.com
  submit().click();

  cy.origin("xxx.onelogin.com", () => {
    cy.get("#password").type("xxx{enter}");
    // Now onelogin.com redirects to my domain /auth/callback but somehow the
    // session cookie is not in the headers. This results in the failure of
    // the callback parameters check.
  });

  // This fails because the server redirected to the login page instead to
  // restart the process.
  cy.url().should("contain", "/home");
});

Cypress Version

13.12.0

Node version

22

Operating System

macOS 14.5

Debug Logs

No response

Other

No response

Tomino2112 commented 1 month ago

I can confirm we are seeing the same issue. Redirect to base domain that happens within different origin does not have the cookies set for base domain (completely missing cookie header). I have tried all sorts of workarounds including intercepting the request and manually injecting the cookie header but none of that worked. Strangely, Cypress seem to ignore anything I have done in the intercept including simple logs, but in the UI would display that the request did match intercept.

Considering the above, it would be something like

cy.intercept('/auth/callback*', (req) => {
  req.headers['cookie'] = 'x-test=hello;'
}).as('authCb');

cy.wait('@authCb').its('request.headers').should('have.property', 'cookie', 'x-test=hello;');

I should also mention that subsequent requests to the base domain (eg loading JS chunks) have the cookie header set correctly

Tomino2112 commented 1 month ago

And of course, a minute after posting the above I have found a "solution". It would seem that the cookie must be set to have no restriction on SameSite and Secure to be true.

cy.setCookie('test', 'hello', {
      domain: cookieDomain,
      path: '/',
      sameSite: 'no_restriction',
      secure: true,
    });

This worked for us, obviously OP is probably not setting the cookie manually so might not work the same