Repository: auth0/auth0.js
Pull request #1158 (2021-03-17 14:29:24)

Apply secure flag to cookies when running on https protocol
### Changes

This PR ensures that any cookies that are set using `CookieStorage.setItem` have the `secure` attribute enabled when using the HTTPS protocol.

### References

See #1050

### Testing

This was tested manually by supplying local CA-trusted certs to `rollup-plugin-serve`, and observing that the cookies now had the secure flag enabled.

- [X] This change adds unit test coverage
- [ ] This change adds integration test coverage

### Checklist

- [X] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md)
- [X] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)
- [X] All tests and linters described in the [Develop section](https://github.com/auth0/auth0.js#develop) run without errors



Patch:
diff --git a/src/helper/storage/cookie.js b/src/helper/storage/cookie.js
index d919f68..5a7e711 100644
--- a/src/helper/storage/cookie.js
+++ b/src/helper/storage/cookie.js
@@ -1,5 +1,6 @@
 import Cookie from 'js-cookie';
 import objectHelper from '../object';
+import windowHandler from '../window';
 function CookieStorage() {}
 
 CookieStorage.prototype.getItem = function(key) {
@@ -17,6 +18,11 @@ CookieStorage.prototype.setItem = function(key, value, options) {
     },
     options
   );
+
+  if (windowHandler.getWindow().location.protocol === 'https:') {
+    params.secure = true;
+  }
+
   Cookie.set(key, value, params);
 };
 


Test patch:
diff --git a/test/helper/storage-handler.test.js b/test/helper/storage-handler.test.js
index 92ace78..d41fa77 100644
--- a/test/helper/storage-handler.test.js
+++ b/test/helper/storage-handler.test.js
@@ -21,7 +21,10 @@ describe('helpers storage handler', function() {
   beforeEach(function() {
     sinon.stub(windowHandler, 'getWindow').callsFake(function(message) {
       return {
-        localStorage: new MockLocalStorage()
+        localStorage: new MockLocalStorage(),
+        location: {
+          protocol: 'http:'
+        }
       };
     });
   });
@@ -40,6 +43,7 @@ describe('helpers storage handler', function() {
     let setItemSpy;
     let getItemStub;
     let removeItemSpy;
+
     beforeEach(function() {
       windowHandler.getWindow.restore();
 
@@ -119,6 +123,7 @@ describe('helpers storage handler', function() {
       var handler = new StorageHandler({ __tryLocalStorageFirst: true });
 
       expect(handler.storage).to.be.a(MockLocalStorage);
+
       handler.setItem('some', 'value', { options: true });
 
       expect(handler.storage).to.be.a(CookieStorage);
diff --git a/test/helper/storage.cookie.test.js b/test/helper/storage.cookie.test.js
index dcfa91d..609bed8 100644
--- a/test/helper/storage.cookie.test.js
+++ b/test/helper/storage.cookie.test.js
@@ -3,6 +3,8 @@ import expect from 'expect.js';
 import sinon from 'sinon';
 
 import CookieStorage from '../../src/helper/storage/cookie';
+import windowHandler from '../../src/helper/window';
+
 var cookieStorage = new CookieStorage();
 const KEY = 'foo';
 const VALUE = 'bar';
@@ -39,21 +41,57 @@ describe('storage.cookies', function() {
     });
   });
   describe('setItem', function() {
+    beforeEach(function() {
+      sinon.stub(windowHandler, 'getWindow').callsFake(function() {
+        return {
+          location: {
+            protocol: 'http:'
+          }
+        };
+      });
+    });
+
+    afterEach(function() {
+      windowHandler.getWindow.restore();
+    });
+
     it('calls Cookie.set with default values', function() {
       cookieStorage.setItem(KEY, VALUE);
+
       expect(CookieLibrary.set.firstCall.args).to.be.eql([
         'foo',
         'bar',
         { expires: 1 }
       ]);
     });
+
     it('calls Cookie.set with custom values', function() {
       cookieStorage.setItem(KEY, VALUE, { expires: 2, test: true });
+
       expect(CookieLibrary.set.firstCall.args).to.be.eql([
         'foo',
         'bar',
         { expires: 2, test: true }
       ]);
     });
+
+    it('sets the secure flag on cookies when using the https protocol', function() {
+      windowHandler.getWindow.restore();
+      sinon.stub(windowHandler, 'getWindow').callsFake(function() {
+        return {
+          location: {
+            protocol: 'https:'
+          }
+        };
+      });
+
+      cookieStorage.setItem(KEY, VALUE, { expires: 2, test: true });
+
+      expect(CookieLibrary.set.firstCall.args).to.be.eql([
+        'foo',
+        'bar',
+        { expires: 2, test: true, secure: true }
+      ]);
+    });
   });
 });
diff --git a/test/web-auth/cross-origin-authentication.test.js b/test/web-auth/cross-origin-authentication.test.js
index 5d8dc1b..fb5724c 100644
--- a/test/web-auth/cross-origin-authentication.test.js
+++ b/test/web-auth/cross-origin-authentication.test.js
@@ -25,9 +25,19 @@ describe('auth0.WebAuth.crossOriginAuthentication', function() {
       });
       global.window = {};
     });
+
     beforeEach(function() {
       sinon.spy(Storage.prototype, 'setItem');
+
+      sinon.stub(windowHelper, 'getWindow').callsFake(function() {
+        return {
+          location: {
+            protocol: 'http:'
+          }
+        };
+      });
     });
+
     afterEach(function() {
       request.post.restore();
       Storage.prototype.setItem.restore();
@@ -38,6 +48,10 @@ describe('auth0.WebAuth.crossOriginAuthentication', function() {
       if (WebMessageHandler.prototype.run.restore) {
         WebMessageHandler.prototype.run.restore();
       }
+
+      if (windowHelper.getWindow.restore) {
+        windowHelper.getWindow.restore();
+      }
     });
     it('should call /co/authenticate and redirect to /authorize with login_ticket using `username`', function() {
       sinon.stub(request, 'post').callsFake(function(url) {
@@ -63,16 +77,20 @@ describe('auth0.WebAuth.crossOriginAuthentication', function() {
           }
         });
       });
+
       this.co.login({
         username: 'me@example.com',
         password: '123456',
         anotherOption: 'foobar'
       });
+
       expect(this.webAuthSpy.authorize.getCall(0).args[0]).to.be.eql({
         username: 'me@example.com',
         loginTicket: 'a_login_ticket',
         anotherOption: 'foobar'
       });
+
+      windowHelper.getWindow.restore();
     });
     it('should call /co/authenticate and redirect to /authorize with login_ticket using `email`', function() {
       sinon.stub(request, 'post').callsFake(function(url) {