Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

When a Cypress click submits a login form, let the application server perform the authentication and assert the result the user would see: a redirect, protected content, or a session cookie. When a test is about a feature behind login rather than login itself, establish authentication through an API request and cache it with cy.session(). Use cy.intercept() to inspect browser traffic caused by the click—not to observe Cypress’s separate cy.request() setup call.

The right approach depends on what the test is meant to prove. Keep at least one test of the real login flow; use reusable programmatic setup for tests that need only an authenticated starting state. Cypress documents both approaches in its end-to-end testing guidance and API testing guide.

Choose the authentication approach that matches the test

Test purpose Use What it verifies
Verify that users can log in Visit the login page, fill and submit the form, then assert authenticated results. The form, browser request, server decision, and post-login UI.
Test a feature that requires a logged-in user Authenticate programmatically, commonly with cy.request() inside cy.session(). The protected feature, without repeating the login UI flow in every test.
Check the browser request caused by a click Register cy.intercept() before clicking, then wait on its alias. Traffic initiated by the application in the browser.
Check an API call made directly by the test Use cy.request() and assert its response. The direct request and server response; it is not browser traffic for interception.

Cypress calls login mission-critical and recommends exercising signup and login through the UI as a real user would. Programmatic login is a complement for other tests, not a reason to remove all UI-login coverage. See Effective E2E testing in Cypress.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Test the actual login click through the UI

Visit the login page, enter test credentials, submit the form, and assert an outcome backed by the server. Adapt selectors and the cookie name to your application; the example illustrates a pattern and is not a tested application-specific test.

it('logs in through the UI', () => {
  cy.visit('/login')
  cy.get('[data-test=username]').type(Cypress.env('username'))
  cy.get('[data-test=password]').type(Cypress.env('password'), { log: false })
  cy.get('form').contains('Log In').click()

  cy.url().should('include', '/dashboard')
  cy.getCookie('your-session-cookie').should('exist')
  cy.get('[data-test=current-user]')
    .should('contain', Cypress.env('username'))
})

Use seeded test accounts rather than personal or production credentials. Keep credentials out of the spec and source control; the example reads them from Cypress environment configuration. Setting log: false for the password avoids displaying the typed value in the Cypress command log.

Assert the strongest useful observable result for your application. A redirect alone can be misleading if the app redirects unauthenticated users too; combine it with authenticated page content or a session indicator when available. A cookie assertion is useful when the app uses a cookie, but it is not appropriate for applications that store authentication another way.

Use an API login and cy.session() for protected-feature tests

If login is not the behavior under test, authenticate once through the server API and let cy.session() cache and restore the browser’s authentication state. Then visit the route needed by the test: restoring a session does not itself navigate to the application page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Cypress.Commands.add('loginByApi', (username, password) => {
  cy.session(
    ['loginByApi', username],
    () => {
      cy.request('POST', '/auth/login', { username, password })
        .its('status')
        .should('eq', 200)
    },
    {
      validate() {
        cy.request('/auth/me')
          .its('status')
          .should('eq', 200)
      },
    }
  )
})

Call the helper before the feature test’s visit:

it('shows the account settings to an authenticated user', () => {
  cy.loginByApi(Cypress.env('username'), Cypress.env('password'))
  cy.visit('/settings')
  cy.get('[data-test=settings-page]').should('be.visible')
})

In a real app, substitute the actual login endpoint, payload, success condition, validation endpoint, and route. The official Cypress API testing guide demonstrates API authentication inside cy.session() and validation against an authenticated endpoint. The cy.session() documentation describes caching and restoration.

Make the session identifier reflect the user identity and any configuration that changes the authenticated state. If roles, tenants, or other settings produce materially different sessions, include them in the identifier. The validation callback helps Cypress detect an expired or stale session instead of letting a later assertion fail confusingly.

Understand how cookies and bearer tokens behave

Cookie-based authentication

cy.request() is issued from Node, but Cypress shares relevant cookies with the browser. It attaches matching browser cookies to requests and applies Set-Cookie values from responses to the browser, respecting expiry and server-side clearing. Thus, an API login response can establish a cookie for a subsequent cy.visit(); a UI login can likewise leave cookies available to later cy.request() calls. This behavior is documented in API testing in Cypress.

If the API login returns success but the page behaves as anonymous, check whether the response actually sets the expected cookie and whether its domain, path, and expiry match the app route. Also verify that the app uses cookie authentication rather than browser storage or another mechanism. Confirm the result with an authenticated endpoint, not only the login response status.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Bearer-token authentication

For an API that expects a bearer token, send it in the authorization header on cy.request(). Keep the token in Cypress environment configuration rather than hard-coding it in a spec. Cypress notes that cy.session() can cache browser storage as well as cookies; make sure your setup and validation reflect the storage mechanism your application actually uses. See the Cypress FAQ for its guidance on authentication tokens and requests.

cy.request({
  method: 'GET',
  url: '/api/profile',
  headers: {
    authorization: `Bearer ${Cypress.env('authToken')}`,
  },
}).its('status').should('eq', 200)

This request example is for a bearer-token API. It does not by itself prove that the browser UI has been authenticated; if the feature test needs an authenticated browser, establish and validate the application’s expected browser state as well.

Intercept the request caused by the click—not the setup request

Register the intercept before the click, then wait for the alias and inspect the browser application’s request or response:

cy.intercept('POST', '/auth/login').as('login')

cy.get('form').contains('Log In').click()

cy.wait('@login').then(({ request, response }) => {
  expect(request.body).to.have.property('username')
  expect(response.statusCode).to.eq(200)
})

Adapt the method, URL, payload assertions, and expected status to the application. Do not assert or print a real password in a test log. If the app uses a different route or sends credentials in a different format, match the request it actually makes.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

cy.intercept() observes requests made by the browser application through Cypress’s proxy. It does not observe a setup request made with cy.request(), which runs from Node outside that proxy. Assert a direct API request through its own cy.request() result; use an intercept when the browser action is what should generate the request. Cypress explains this distinction in its API guide and FAQ.

Handle SSO and cross-origin identity providers

If the login flow redirects to an identity provider on another origin and the test continues by issuing Cypress commands there, use cy.origin() for that origin. Cypress identifies SSO, OAuth, OIDC, and authentication-as-a-service providers as common cross-origin cases. See Cross origin testing in Cypress for the current command guidance.

The right scope depends on the test: exercise the provider interaction when that interaction is what you need to cover; use programmatic authentication when the test is about your application’s behavior and the provider UI is outside its purpose. Cypress documents API-based login as an option for avoiding repeated third-party login flows. Do not treat a redirect to another origin as though it were still the application’s original origin.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Test redirects and expected authentication errors deliberately

By default, cy.request() follows redirects. If a test needs to inspect the original redirect response—for example, to verify that an unauthenticated request is sent to login—set followRedirect: false and assert the response’s redirectedToUrl. For an expected 4xx or 5xx response, set failOnStatusCode: false so Cypress lets the test inspect it instead of failing immediately.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
cy.request({
  url: '/protected',
  followRedirect: false,
}).then((response) => {
  expect(response.status).to.be.oneOf([301, 302, 303, 307, 308])
  expect(response.redirectedToUrl).to.include('/login')
})

cy.request({
  url: '/api/protected',
  failOnStatusCode: false,
}).then((response) => {
  expect(response.status).to.eq(401)
})

Use the redirect status codes and destination your server actually returns. The API options and their expected-response behavior are covered in the API testing guide and FAQ.

Troubleshoot authentication tests

  • An intercept wait times out for an API login helper. The helper’s cy.request() is a Node-side request, not browser traffic. Assert its response directly, or intercept the browser request generated by the UI click.
  • The login request succeeds but the next page is anonymous. Inspect the response’s Set-Cookie and verify the cookie’s domain, path, and expiry; confirm that the app uses cookie authentication; then validate against an authenticated endpoint.
  • The test restores a session but remains on the wrong page. Session restoration and navigation are separate. Call cy.visit() for the route under test after the session setup.
  • The redirect assertion sees the destination instead of the first response. Redirect following is enabled by default for cy.request(). Set followRedirect: false when you need to inspect the initial response.
  • A test of unauthorized behavior fails before its assertion. Set failOnStatusCode: false when the non-success response is expected and should be asserted explicitly.
  • Commands fail after the login flow moves to an identity-provider origin. Use cy.origin() when issuing commands on that different origin.
  • A cached session is rejected by the application. Check the validate() callback, session identifier inputs, authentication expiry, and the endpoint used to confirm current authentication.

Or skip the browser setup

ScreenshotNeo is a website screenshot API, not an authentication-testing substitute. It can capture a URL for visual review, but it does not click Cypress controls or establish your application’s authenticated browser session. For that separate screenshot task, its API accepts a URL in one GET request. See the ScreenshotNeo site and API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month with no card.

Frequently Asked Questions

Why doesn’t cy.intercept() match cy.request() calls in Cypress?

cy.request() runs from Node, outside the browser proxy observed by cy.intercept(). Assert the direct request’s response, or intercept a request initiated by the browser application.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do I send an authentication token with cy.request() in Cypress?

Pass it in the authorization header, typically as Bearer YOUR_TOKEN, and store the token in environment configuration rather than in the spec.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.