0

The csrf cookie sent by my backend seems to be ignored by browsers.

Request and Response

The request is being made via Angular (2) from http://localhost.mydomain.com:4200 like so:

get() {
  let headers = new Headers({
    'Content-Type'    : 'application/json',
    'withCredentials' : true
  });
  let options = new RequestOptions({headers : headers});
  return this.http.post('https://api.mydomain.com', {
    o : 'csrf',
    m : 'get',
    p : {}
  }, options)
    .map((res: Response) => {
      console.log('response received: ', res)
    })
    .catch((err: any) => {
      console.log('error received: ', err);
      return Observable.throw(err);
    });
}

The request is being received by AWS API Gateway/Lambda running Express 4.x and sent back as:

res.cookie('csrf', token, {domain : '.mydomain.com'});

Setting cookies on xhr responses should be fine. Because both the request and response are subdomains of mydomain.com I shouldn't need the withCredentials option (though, as shown, I tried sending it anyway). The response is received and the header is there. It's just not being set.

It's being ignored in Chrome, Firefox and IE so I'm sure the problem is I'm missing something obvious :)

Roy Reiss
  • 873
  • 9
  • 19
  • 2
    note that different subdomain is considered cross origin by browser so you would need withCredentials for all requests to api – charlietfl Feb 01 '17 at 18:30
  • 2
    In addition to what @charlietfl (correctly) states, `withCredentials` is not a header but [a property of `XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials). – robertklep Feb 01 '17 at 18:36
  • D'oh! That was it. Thanks!! – Roy Reiss Feb 01 '17 at 18:45

1 Answers1

0

For anyone that stumbles on this @robertklep and @charliefl were correct (thanks!). The correct way to write my request was:

get() {
  let headers = new Headers({
    'Content-Type'    : 'application/json'
  });
  let options = new RequestOptions({
    headers : headers,
    withCredentials: true
  });
  return this.http.post('https://api.mydomain.com', {
    o : 'csrf',
    m : 'get',
    p : {}
  }, options)
    .map((res: Response) => {
      console.log('response received: ', res)
    })
    .catch((err: any) => {
      console.log('error received: ', err);
      return Observable.throw(err);
    });
}

In addition, because I was trying to be lazy and use a wildcard in the 'Access-Control-Allow-Origin' on my server I then ran into the error:

 A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true

If you have multiple domains consuming your API you'll have to set the 'Access-Control-Allow-Origin' dynamically on your server as discussed here and here depending on what domains/subdomains you want to allow.

Community
  • 1
  • 1
Roy Reiss
  • 873
  • 9
  • 19