skip to Main Content

I am trying to access audio snippets within an application hosted on Azure blob storage during a cypress test and I keep getting

"403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature."

The app works fine when I use it manually through browser, but fails during Cypress run.

this is my cypress config

const { defineConfig } = require("cypress");

module.exports = defineConfig({
  e2e: {
    baseUrl: 'https://tts-sa-dev.azurewebsites.net',
    setupNodeEvents(on, config) {
      // implement node event listeners here 
    },
  },
});

I use a basic auth before every test suite

beforeEach(() => cy.authenticate('basic')); 

that looks like this


Cypress.Commands.add('authenticate', (authType: 'basic') => {
  if (authType === 'basic') {
    
    const username = 'XXXX'; 
    const password = 'XXXX'; 
    const authHeader = 'Basic ' + btoa(username + ':' + password);

    // Intercept all requests and add the Authorization header
    cy.intercept('**', (req) => {
      req.headers['Authorization'] = authHeader;
    });
  }
});

Im not sure if the auth header could be somehow interacting with the cors signature from azure and there seems to be nobody else on stackoverflow dealing with this, which i find strange.

I’ve simplified the test to bare bones, but it fails to retrieve any data after calling the endpoint.
I realize cypress is probably modifying the request header but I fail to log any difference when intercepting it.

Anybody has a similar problem?

I have compared request headers and there were some discrepancies:
There was an "origin" header missing, "accept" was an array of options and "fetch-mode" was non-cors, but adjusting them made no difference.


cy.intercept('*', (req) => {
      console.log('Request Headers at Intercept:', req.headers);
      req.headers['Accept'] = 'application/json';
      req.headers['Origin'] = 'https://xxxx.azurewebsites.net';
      req.headers['Sec-Fetch-Mode'] = 'cors';
      req.headers['Accept-Language'] = 'cs,en;q=0.9';
    });

2

Answers


  1. Chosen as BEST ANSWER

    Ok so I've found a solution - the problem seems to be in the basic auth

    beforeEach(() => cy.authenticate('basic')); 
    

    Azure has some kind of a problem with basic auth and doesn't do well with authorization header.

    Instead I have used

    beforeEach(() => cy.visit('https://username:[email protected]'));
    

    Works fine now


  2. I think you need header names to start lower case.

    If you look at Passing a request to the next request handler, it uses lower-case authorization but you have upper-case Authorization.

    cy.intercept('http://api.company.com/', { middleware: true }, (req) => {
      req.headers['authorization'] = `token ${token}`
    })
    

    If I try a sample test with req.headers['Origin'] it passes (but it shouldn’t)

    cy.intercept(/todos/, (req) => {
    
      const defaultHeaders = Cypress._.cloneDeep(req.headers)
      console.log('Request Headers at Intercept:', defaultHeaders)
    
      req.headers['Accept'] = 'application/json';
      req.headers['Origin'] = 'https://xxxx.azurewebsites.net';
      req.headers['Sec-Fetch-Mode'] = 'cors';
      req.headers['Accept-Language'] = 'cs,en;q=0.9';
    })
    .as('request-headers')
    
    cy.window().then(win => {
      win.fetch('https://jsonplaceholder.typicode.com/todos/1')
    })  
    
    cy.wait('@request-headers').then(({request,response}) => {
      console.log(request.headers)
      expect(request.headers['Origin']).to.eq('https://xxxx.azurewebsites.net')
    })
    

    In the final console.log() there are upper-case and lower-case headers for "Origin/origin" keys, which indicates the header key is case sensitive.

    Origin: "https://xxxx.azurewebsites.net",
    origin: "http://localhost:34272"
    

    If I switch to lower-case req.headers['origin'] it now fails with a CORS error, which I think is correct behavior.

    From that I would conclude the correct format for setting header keys is to use lower-case strings.

    Not sure this is the complete answer, but should get you one step further.


    Basic auth on cy.visit()

    The cy.visit() – Add basic auth headers documentation shows how to use basic auth in the visit command.

    cy.visit('https://wile:[email protected]/')
    
    or
    
    cy.visit('https://tts-sa-dev.azurewebsites.net/', {
      auth: {
        username: 'wile',
        password: 'coyote',
      },
    })
    

    This should make a single test test authenticated, push to beforeEach() to do it for each test.

    Wrap in a cy.session to cache the login credentials.

    Cypress.Commands.add('login', (username, password) => {
      cy.session([username, password], () => {
        cy.visit('https://wile:[email protected]/')
      })
    })
    
    beforeEach(() => {
      cy.login('wile', 'coyote')
    })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search