Repository: auth0/auth0.js
Pull request #1217 (2021-10-27 14:08:58)

Make state expiration configurable
### Overview
Currently, the cookie expiration for state is pinned to 30 minutes (that PR [here](https://github.com/auth0/auth0.js/pull/835)). My company has a business use case to make that longer (probably 1-2 hours), however, I could see a business use case to keep that shorter than 30 minutes.
This change will make this value configurable through `WebAuth`, as a passed in option.
If this option is not passed in, current functionality is retained at 30 minutes. 

### Changes
* `WebAuth` accepts a new param on options.
  * `stateExpiration` - number of minutes for the state to expire in (please provide any name suggestions if as coded could be more explicit)
  * This is required to pass through the option to `TransactionManager`
* `TransactionManager` accepts the same option
  * Defaults to the existing 30 minutes

### Testing

* Configure `TransactionManager` with a `stateExpiration` with a value other than `30`
* Run `generateTransaction`, and see the cookie be set to expire in the given timeframe

- [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


aedelbro: @stevehobbsdev Do you have any general estimate on when this might get rolled into a release? 
stevehobbsdev: Yes, hoping to get this release out today 🙌

Patch:
diff --git a/src/web-auth/index.js b/src/web-auth/index.js
index 6685c92..8289c9e 100644
--- a/src/web-auth/index.js
+++ b/src/web-auth/index.js
@@ -35,6 +35,7 @@ function defaultClock() {
  * @param {String} [options.audience] identifier of the resource server who will consume the access token issued after Auth
  * @param {Number} [options.leeway] number of seconds to account for clock skew when validating time-based claims in ID tokens. Defaults to 60 seconds.
  * @param {Number} [options.maxAge] maximum elapsed time in seconds since the last time the user was actively authenticated by the authorization server.
+ * @param {Number} [options.stateExpiration] number of minutes for the stored state to be kept. Defaults to 30 minutes.
  * @param {String} [options.organization] the Id of an organization to log in to
  * @param {String} [options.invitation] the ID of an invitation to accept. This is available from the user invitation URL that is given when participating in a user invitation flow
  * @param {Array} [options.plugins]
@@ -90,6 +91,11 @@ function WebAuth(options) {
         type: 'number',
         message: 'maxAge is not valid'
       },
+      stateExpiration: {
+        optional: true,
+        type: 'number',
+        message: 'stateExpiration is not valid'
+      },
       _disableDeprecationWarnings: {
         optional: true,
         type: 'boolean',
diff --git a/src/web-auth/transaction-manager.js b/src/web-auth/transaction-manager.js
index 4f7f14d..5aa0b5d 100644
--- a/src/web-auth/transaction-manager.js
+++ b/src/web-auth/transaction-manager.js
@@ -9,6 +9,8 @@ function TransactionManager(options) {
   var transaction = options.transaction || {};
   this.namespace = transaction.namespace || DEFAULT_NAMESPACE;
   this.keyLength = transaction.keyLength || 32;
+  // Passed option is in minutes, convert to days
+  this.stateExpiration = options.stateExpiration ? (options.stateExpiration / 60 / 24) : times.MINUTES_30;
   this.storage = new Storage(options);
   this.options = options;
 }
@@ -68,7 +70,7 @@ TransactionManager.prototype.generateTransaction = function(
     }
 
     this.storage.setItem(this.namespace + state, transactionPayload, {
-      expires: times.MINUTES_30
+      expires: this.stateExpiration
     });
   }
 


Test patch:
diff --git a/test/web-auth/transaction-manager.test.js b/test/web-auth/transaction-manager.test.js
index 14182db..086ccce 100644
--- a/test/web-auth/transaction-manager.test.js
+++ b/test/web-auth/transaction-manager.test.js
@@ -228,7 +228,7 @@ context('TransactionManager', function() {
           lastUsedConnection: 'lastUsedConnection'
         });
       });
-      it('stores state with expires option equal to 30 mins', function() {
+      it('stores state with expires option equal to 30 mins by default', function () {
         this.tm.generateTransaction(
           'appState',
           'providedState',
@@ -243,7 +243,26 @@ context('TransactionManager', function() {
           expires: times.MINUTES_30
         });
       });
-      it('stores the organization ID when given', function() {
+      it('stores state with expires option equal to X mins if passed in', function () {
+        this.tm = new TransactionManager({
+          domain: 'myapp.auth0.com',
+          stateExpiration: 60 //minutes
+        });
+        this.tm.generateTransaction(
+          'appState',
+          'providedState',
+          'providedNonce',
+          null
+        );
+        expect(Storage.prototype.setItem.calledOnce).to.be(true);
+        expect(typeof Storage.prototype.setItem.lastCall.args[2]).to.be(
+          'object'
+        );
+        expect(Storage.prototype.setItem.lastCall.args[2]).to.be.eql({
+          expires: 1 / 24 //days
+        });
+      });
+      it('stores the organization ID when given', function () {
         this.tm.generateTransaction(
           'appState',
           'providedState',