4

I am trying to implement an authentication service deployed in a different HTTP server from the one serving my login page.

The following diagram depicts my setup: enter image description here

On step #1 my browser makes an HTTP GET request to fetch the login page. This is provided as the HTTP response in #2. My browser renders the login page and when I click the login button I send an HTTP POST to a different server (on the same localhost). This is done in #3. The authentication server checks the login details and sends a response that sets the cookie in #4.

The ajax POST request in #3 is made using jQuery:

$.post('http://127.0.0.1:8080/auth-server/some/path/',
       {username: 'foo', password: 'foo'},
       someCallback);

The authentication service's response (assuming authentication was successful) has the following header:

HTTP/1.1 200
Set-Cookie: session-id=v3876gc9jf22krlun57j6ellaq;Version=1
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: origin, content-type, accept, authorization
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, HEAD
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 21 Nov 2016 16:17:08 GMT

So the cookie (session-id) is present in the HTTP response in step #4.

Now if the user tries to login again I would like the authentication service to detect that. To test that scenario I press the login button again in order to repeat the post in #3. I would have expected the second request to contain the cookie. However the second time I press the login button, the request header in the post sent out in #3 does not contain the cookie.

What I have discovered is that for the post in #3 to contain the cookie, I have to do it like this:

        $.ajax({
            type: 'post',
            url: 'http://127.0.0.1:8080/auth-server/some/path',
            crossDomain: true,
            dataType: 'text',
            xhrFields: {
                withCredentials: true
            },
            data: {
                username : 'foo',
                password : 'foo',
            },
            success: someCallback
        });

Why would that be necessary? MDN states that this is only required for cross-site requests. This SO post also uses xhrFields but only in relation to a cross-domain scenario. I understand that my case is not cross-domain as both the page that serves the script is on localhost, and the page to where the ajax request is sent is on the same host. I also understand that cookie domains are not port specific. Moreover, since my cookie did not explicitly specify a domain, then the effective domain is that of the request meaning 127.0.0.1 which is identical the second time I send the POST request (#3). Finally, the HTTP reponse on #4 already includes Access-Control-Allow-Origin: * which means that the resource can be accessed by any domain in a cross-site manner.

So why did I have to use the xhrFields: {withCredentials: true} to make this work?

What I understand is that setting Access-Control-Allow-Origin: * is simply enabling cross-site requests but that in order for cookies to be sent then the xhrFields: {withCredentials: true} should be used regardless (as explained in MDN section on requests with credentials). Moreover, I understand that the request is indeed cross-site since the port number is important when deciding whether a request is cross-site or not. Whether the domain of a cookie includes ports is irrelevant. Is this understanding correct?

update

I think this is explained very clearly in this answer, so maybe this question should be deleted.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Marcus Junius Brutus
  • 26,087
  • 41
  • 189
  • 331
  • 1
    yes, but they use different ports... this is already considered CORS – Legends Nov 21 '16 at 18:21
  • So are localhost:3000 & localhost:4000 same-site or cross-site ? I understand they are cross-origin but what about site ? In MDN docs for withCredentials, it talks about same-site not origin – Yusuf Apr 21 '22 at 04:09

1 Answers1

4

All parts of the origin must match the host(ajax target) for it to be considered same-origin. The 3 part of the origin https://sales.company.com:9443 for example includes:

  1. protocol/scheme (https - won't match http)
  2. hostname (sales.company.com - won't match subdomain.sales.company.com)
  3. port (9443 - won't match 443)

enter image description here

see https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy

claya
  • 1,920
  • 1
  • 18
  • 32
  • 1
    So are localhost:3000 & localhost:4000 same-site or cross-site ? I understand they are cross-origin but what about site ? In MDN docs for withCredentials, it talks about same-site not origin – Yusuf Apr 21 '22 at 04:09