diff --git a/README.md b/README.md index 9eed15b..7cc0647 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,6 @@ The default CommonJS import path does not assign or polyfill `window.fetch`. Use exclusively handled by the browser's internal mechanisms which this polyfill cannot influence. -* If you have trouble **maintaining the user's session** or [CSRF][] protection - through `fetch` requests, please ensure that you've read and understood the - [Sending cookies](#sending-cookies) section. `fetch` doesn't send cookies - unless you ask it to. - * This project **doesn't work under Node.js environments**. It's meant for web browsers only. You should ensure that your application doesn't try to package and run this on the server. @@ -178,18 +173,14 @@ fetch('/avatars', { ### Caveats -The actual `fetch` specification differs from `jQuery.ajax()` in mainly two ways that -bear keeping in mind: - * The Promise returned from `fetch()` **won't reject on HTTP error status** even if the response is an HTTP 404 or 500. Instead, it will resolve normally, and it will only reject on network failure or if anything prevented the request from completing. -* By default, `fetch` **won't send or receive any cookies** from the server, - resulting in unauthenticated requests if the site relies on maintaining a user - session. See [Sending cookies](#sending-cookies) for how to opt into cookie - handling. +* For maximum browser compatibility when it comes to sending & receiving + cookies, always supply the `credentials: 'same-origin'` option instead of + relying on the default. See [Sending cookies](#sending-cookies). #### Handling HTTP error statuses @@ -223,25 +214,41 @@ fetch('/users') #### Sending cookies -To automatically send cookies for the current domain, the `credentials` option -must be provided: +For [CORS][] requests, use `credentials: 'include'` to allow sending credentials +to other domains: + +```javascript +fetch('https://example.com:1234/users', { + credentials: 'include' +}) +``` + +To disable sending or receiving cookies for requests to any domain, including +the current one, use the "omit" value: ```javascript fetch('/users', { - credentials: 'same-origin' + credentials: 'omit' }) ``` -The "same-origin" value makes `fetch` behave similarly to XMLHttpRequest with -regards to cookies. Otherwise, cookies won't get sent, resulting in these -requests not preserving the authentication session. +The default value for `credentials` is "same-origin". + +The default for `credentials` wasn't always the same, though. The following +versions of browsers implemented an older version of the fetch specification +where the default was "omit": -For [CORS][] requests, use the "include" value to allow sending credentials to -other domains: +* Firefox 39-60 +* Chrome 42-67 +* Safari 10.1-11.1.2 + +If you target these browsers, it's advisable to always specify `credentials: +'same-origin'` explicitly with all fetch requests instead of relying on the +default: ```javascript -fetch('https://example.com:1234/users', { - credentials: 'include' +fetch('/users', { + credentials: 'same-origin' }) ``` @@ -253,10 +260,6 @@ read with `response.headers.get()`. Instead, it's the browser's responsibility to handle new cookies being set (if applicable to the current URL). Unless they are HTTP-only, new cookies will be available through `document.cookie`. -Bear in mind that the default behavior of `fetch` is to ignore the `Set-Cookie` -header completely. To opt into accepting cookies from the server, you must use -the `credentials` option. - #### Obtaining the Response URL Due to limitations of XMLHttpRequest, the `response.url` value might not be diff --git a/test/test.js b/test/test.js index d1280b1..fd639ed 100644 --- a/test/test.js +++ b/test/test.js @@ -636,6 +636,16 @@ exercise.forEach(function(exerciseMode) { testBodyExtract(function(body) { return new Request('', {method: 'POST', body: body}) }) + + test('credentials defaults to same-origin', function() { + var request = new Request('') + assert.equal(request.credentials, 'same-origin') + }) + + test('credentials is overridable', function() { + var request = new Request('', {credentials: 'omit'}) + assert.equal(request.credentials, 'omit') + }) }) // https://fetch.spec.whatwg.org/#response-class @@ -1457,24 +1467,6 @@ exercise.forEach(function(exerciseMode) { }) featureDependent(suite, exerciseMode === 'native', 'omit', function() { - test('request credentials defaults to omit', function() { - var request = new Request('') - assert.equal(request.credentials, 'omit') - }) - - test('does not accept cookies with implicit omit credentials', function() { - return fetch('/cookie?name=foo&value=bar') - .then(function() { - return fetch('/cookie?name=foo', {credentials: 'same-origin'}) - }) - .then(function(response) { - return response.text() - }) - .then(function(data) { - assert.equal(data, 'reset') - }) - }) - test('does not accept cookies with omit credentials', function() { return fetch('/cookie?name=foo&value=bar', {credentials: 'omit'}) .then(function() { @@ -1488,19 +1480,6 @@ exercise.forEach(function(exerciseMode) { }) }) - test('does not send cookies with implicit omit credentials', function() { - return fetch('/cookie?name=foo&value=bar', {credentials: 'same-origin'}) - .then(function() { - return fetch('/cookie?name=foo') - }) - .then(function(response) { - return response.text() - }) - .then(function(data) { - assert.equal(data, '') - }) - }) - test('does not send cookies with omit credentials', function() { return fetch('/cookie?name=foo&value=bar') .then(function() { @@ -1516,11 +1495,6 @@ exercise.forEach(function(exerciseMode) { }) suite('same-origin', function() { - test('request credentials uses inits member', function() { - var request = new Request('', {credentials: 'same-origin'}) - assert.equal(request.credentials, 'same-origin') - }) - test('send cookies with same-origin credentials', function() { return fetch('/cookie?name=foo&value=bar', {credentials: 'same-origin'}) .then(function() {