node jwt: How can I send a new token when the old one expires?











up vote
0
down vote

favorite












I'm working on a game that requires the user to sign in, so I send a token with an expiry of 24 hours so the user doesn't have to sign in.



My understanding (and possibly, handling) of the tokens is crude, but so far it does what I need it to (allows user to auto-login by submitting the token, can't access most of the APIs without a valid token, and forces the user to log in after 24 hrs).



However, I ran into an issue that while playing the game and submitting my score, the token expired, and thus was prevented from updating my score.



So I thought why not issue a new one when it is expired? Perhaps the APIs can take that expired token and issue a new one? Well, I tried.



Here's my code so far:



signToken: function(p_userId, p_isRefresh) {
return new Promise((resolve, reject) => {
const tokenUuid = uuidv4();
const connection = dbConnMysql.createConnection();
dbConnMysql.startConnection(connection).then(() => {
// Adds user ID, UUID, and expiry to DB
}).then(() => {
return dbConnMysql.closeConnection(connection).then(() => {
const payload = {
'id':p_userId,
'uuid':tokenUuid
};
let token = jwt.sign(payload, appcfg['tkSecret'], {expiresIn: 120}); //86400 for 24 hrs
var response = {};
if (!p_isRefresh || p_isRefresh === null) {
response = {'token':token};
} else if (p_isRefresh) {
let tokenStatus = {'isValid':true, 'reason':"Token Valid", 'id':p_userId, 'uuid':tokenUuid, 'token':token};
var response = {'statusCode': 200, 'message': JSON.stringify(tokenStatus)};
}
resolve(response);
});
}).catch((error) => {
// Error Handling
});

});
},

validateToken: function(p_token, p_isActive) {
return new Promise((resolve, reject) => {
let decodedToken = jwt.verify(p_token, appcfg['tkSecret']);
let dateNow = new Date();
if (decodedToken.exp > dateNow.getTime() / 1000) {
const connection = dbConnMysql.createConnection();
dbConnMysql.startConnection(connection).then(() => {
// Checks if UUID is in DB
}).then((fulfilled) => {
return dbConnMysql.closeConnection(connection)
.then(() => {
// If UUID is in DB, resolve with token, else, reject with message 'Token not valid'
})
.catch((error) => {
// Error Handling
});

})
} else {
if (!p_isActive) {
// Token was not in use when it became invalid, reject. Deletes entry in DB.
} else {
// Token was in use when it became invalid, create a new one.
dbConnMysql.startConnection(connection).then(() => {
// Delete expired token
}).then(() => {
return this.signToken(decodedToken.id, true);
});
}

}
});
}


My problem is that it doesn't even bother checking the database; once the code line



let decodedToken = jwt.verify(p_token, appcfg['tkSecret']);


is hit, it throws an error, saying the token is expired, seemingly* making the rest of my code useless. I'm wondering what the simplest work around or solution is to this problem; as much as I'd like to delve into solutions that I would need to read up on and study (such as sending refresh tokens), I am pressed for time, and the game itself is rather rigid and hard to change as of now.



A possible solution that I can think of is that instead of issuing a new token when the old one is expired, I could issue a new one X hours / minutes / seconds before it actually does, but that (probably) has its own set of problems, so I'm open to hearing other ideas.



Or... why does it completely break the code when the token is expired?



*I console logged out every catch and then block, but near as I can tell, it's the outer-most catch catches the error with this:




TokenExpiredError: jwt expired




Thanks.










share|improve this question


























    up vote
    0
    down vote

    favorite












    I'm working on a game that requires the user to sign in, so I send a token with an expiry of 24 hours so the user doesn't have to sign in.



    My understanding (and possibly, handling) of the tokens is crude, but so far it does what I need it to (allows user to auto-login by submitting the token, can't access most of the APIs without a valid token, and forces the user to log in after 24 hrs).



    However, I ran into an issue that while playing the game and submitting my score, the token expired, and thus was prevented from updating my score.



    So I thought why not issue a new one when it is expired? Perhaps the APIs can take that expired token and issue a new one? Well, I tried.



    Here's my code so far:



    signToken: function(p_userId, p_isRefresh) {
    return new Promise((resolve, reject) => {
    const tokenUuid = uuidv4();
    const connection = dbConnMysql.createConnection();
    dbConnMysql.startConnection(connection).then(() => {
    // Adds user ID, UUID, and expiry to DB
    }).then(() => {
    return dbConnMysql.closeConnection(connection).then(() => {
    const payload = {
    'id':p_userId,
    'uuid':tokenUuid
    };
    let token = jwt.sign(payload, appcfg['tkSecret'], {expiresIn: 120}); //86400 for 24 hrs
    var response = {};
    if (!p_isRefresh || p_isRefresh === null) {
    response = {'token':token};
    } else if (p_isRefresh) {
    let tokenStatus = {'isValid':true, 'reason':"Token Valid", 'id':p_userId, 'uuid':tokenUuid, 'token':token};
    var response = {'statusCode': 200, 'message': JSON.stringify(tokenStatus)};
    }
    resolve(response);
    });
    }).catch((error) => {
    // Error Handling
    });

    });
    },

    validateToken: function(p_token, p_isActive) {
    return new Promise((resolve, reject) => {
    let decodedToken = jwt.verify(p_token, appcfg['tkSecret']);
    let dateNow = new Date();
    if (decodedToken.exp > dateNow.getTime() / 1000) {
    const connection = dbConnMysql.createConnection();
    dbConnMysql.startConnection(connection).then(() => {
    // Checks if UUID is in DB
    }).then((fulfilled) => {
    return dbConnMysql.closeConnection(connection)
    .then(() => {
    // If UUID is in DB, resolve with token, else, reject with message 'Token not valid'
    })
    .catch((error) => {
    // Error Handling
    });

    })
    } else {
    if (!p_isActive) {
    // Token was not in use when it became invalid, reject. Deletes entry in DB.
    } else {
    // Token was in use when it became invalid, create a new one.
    dbConnMysql.startConnection(connection).then(() => {
    // Delete expired token
    }).then(() => {
    return this.signToken(decodedToken.id, true);
    });
    }

    }
    });
    }


    My problem is that it doesn't even bother checking the database; once the code line



    let decodedToken = jwt.verify(p_token, appcfg['tkSecret']);


    is hit, it throws an error, saying the token is expired, seemingly* making the rest of my code useless. I'm wondering what the simplest work around or solution is to this problem; as much as I'd like to delve into solutions that I would need to read up on and study (such as sending refresh tokens), I am pressed for time, and the game itself is rather rigid and hard to change as of now.



    A possible solution that I can think of is that instead of issuing a new token when the old one is expired, I could issue a new one X hours / minutes / seconds before it actually does, but that (probably) has its own set of problems, so I'm open to hearing other ideas.



    Or... why does it completely break the code when the token is expired?



    *I console logged out every catch and then block, but near as I can tell, it's the outer-most catch catches the error with this:




    TokenExpiredError: jwt expired




    Thanks.










    share|improve this question
























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I'm working on a game that requires the user to sign in, so I send a token with an expiry of 24 hours so the user doesn't have to sign in.



      My understanding (and possibly, handling) of the tokens is crude, but so far it does what I need it to (allows user to auto-login by submitting the token, can't access most of the APIs without a valid token, and forces the user to log in after 24 hrs).



      However, I ran into an issue that while playing the game and submitting my score, the token expired, and thus was prevented from updating my score.



      So I thought why not issue a new one when it is expired? Perhaps the APIs can take that expired token and issue a new one? Well, I tried.



      Here's my code so far:



      signToken: function(p_userId, p_isRefresh) {
      return new Promise((resolve, reject) => {
      const tokenUuid = uuidv4();
      const connection = dbConnMysql.createConnection();
      dbConnMysql.startConnection(connection).then(() => {
      // Adds user ID, UUID, and expiry to DB
      }).then(() => {
      return dbConnMysql.closeConnection(connection).then(() => {
      const payload = {
      'id':p_userId,
      'uuid':tokenUuid
      };
      let token = jwt.sign(payload, appcfg['tkSecret'], {expiresIn: 120}); //86400 for 24 hrs
      var response = {};
      if (!p_isRefresh || p_isRefresh === null) {
      response = {'token':token};
      } else if (p_isRefresh) {
      let tokenStatus = {'isValid':true, 'reason':"Token Valid", 'id':p_userId, 'uuid':tokenUuid, 'token':token};
      var response = {'statusCode': 200, 'message': JSON.stringify(tokenStatus)};
      }
      resolve(response);
      });
      }).catch((error) => {
      // Error Handling
      });

      });
      },

      validateToken: function(p_token, p_isActive) {
      return new Promise((resolve, reject) => {
      let decodedToken = jwt.verify(p_token, appcfg['tkSecret']);
      let dateNow = new Date();
      if (decodedToken.exp > dateNow.getTime() / 1000) {
      const connection = dbConnMysql.createConnection();
      dbConnMysql.startConnection(connection).then(() => {
      // Checks if UUID is in DB
      }).then((fulfilled) => {
      return dbConnMysql.closeConnection(connection)
      .then(() => {
      // If UUID is in DB, resolve with token, else, reject with message 'Token not valid'
      })
      .catch((error) => {
      // Error Handling
      });

      })
      } else {
      if (!p_isActive) {
      // Token was not in use when it became invalid, reject. Deletes entry in DB.
      } else {
      // Token was in use when it became invalid, create a new one.
      dbConnMysql.startConnection(connection).then(() => {
      // Delete expired token
      }).then(() => {
      return this.signToken(decodedToken.id, true);
      });
      }

      }
      });
      }


      My problem is that it doesn't even bother checking the database; once the code line



      let decodedToken = jwt.verify(p_token, appcfg['tkSecret']);


      is hit, it throws an error, saying the token is expired, seemingly* making the rest of my code useless. I'm wondering what the simplest work around or solution is to this problem; as much as I'd like to delve into solutions that I would need to read up on and study (such as sending refresh tokens), I am pressed for time, and the game itself is rather rigid and hard to change as of now.



      A possible solution that I can think of is that instead of issuing a new token when the old one is expired, I could issue a new one X hours / minutes / seconds before it actually does, but that (probably) has its own set of problems, so I'm open to hearing other ideas.



      Or... why does it completely break the code when the token is expired?



      *I console logged out every catch and then block, but near as I can tell, it's the outer-most catch catches the error with this:




      TokenExpiredError: jwt expired




      Thanks.










      share|improve this question













      I'm working on a game that requires the user to sign in, so I send a token with an expiry of 24 hours so the user doesn't have to sign in.



      My understanding (and possibly, handling) of the tokens is crude, but so far it does what I need it to (allows user to auto-login by submitting the token, can't access most of the APIs without a valid token, and forces the user to log in after 24 hrs).



      However, I ran into an issue that while playing the game and submitting my score, the token expired, and thus was prevented from updating my score.



      So I thought why not issue a new one when it is expired? Perhaps the APIs can take that expired token and issue a new one? Well, I tried.



      Here's my code so far:



      signToken: function(p_userId, p_isRefresh) {
      return new Promise((resolve, reject) => {
      const tokenUuid = uuidv4();
      const connection = dbConnMysql.createConnection();
      dbConnMysql.startConnection(connection).then(() => {
      // Adds user ID, UUID, and expiry to DB
      }).then(() => {
      return dbConnMysql.closeConnection(connection).then(() => {
      const payload = {
      'id':p_userId,
      'uuid':tokenUuid
      };
      let token = jwt.sign(payload, appcfg['tkSecret'], {expiresIn: 120}); //86400 for 24 hrs
      var response = {};
      if (!p_isRefresh || p_isRefresh === null) {
      response = {'token':token};
      } else if (p_isRefresh) {
      let tokenStatus = {'isValid':true, 'reason':"Token Valid", 'id':p_userId, 'uuid':tokenUuid, 'token':token};
      var response = {'statusCode': 200, 'message': JSON.stringify(tokenStatus)};
      }
      resolve(response);
      });
      }).catch((error) => {
      // Error Handling
      });

      });
      },

      validateToken: function(p_token, p_isActive) {
      return new Promise((resolve, reject) => {
      let decodedToken = jwt.verify(p_token, appcfg['tkSecret']);
      let dateNow = new Date();
      if (decodedToken.exp > dateNow.getTime() / 1000) {
      const connection = dbConnMysql.createConnection();
      dbConnMysql.startConnection(connection).then(() => {
      // Checks if UUID is in DB
      }).then((fulfilled) => {
      return dbConnMysql.closeConnection(connection)
      .then(() => {
      // If UUID is in DB, resolve with token, else, reject with message 'Token not valid'
      })
      .catch((error) => {
      // Error Handling
      });

      })
      } else {
      if (!p_isActive) {
      // Token was not in use when it became invalid, reject. Deletes entry in DB.
      } else {
      // Token was in use when it became invalid, create a new one.
      dbConnMysql.startConnection(connection).then(() => {
      // Delete expired token
      }).then(() => {
      return this.signToken(decodedToken.id, true);
      });
      }

      }
      });
      }


      My problem is that it doesn't even bother checking the database; once the code line



      let decodedToken = jwt.verify(p_token, appcfg['tkSecret']);


      is hit, it throws an error, saying the token is expired, seemingly* making the rest of my code useless. I'm wondering what the simplest work around or solution is to this problem; as much as I'd like to delve into solutions that I would need to read up on and study (such as sending refresh tokens), I am pressed for time, and the game itself is rather rigid and hard to change as of now.



      A possible solution that I can think of is that instead of issuing a new token when the old one is expired, I could issue a new one X hours / minutes / seconds before it actually does, but that (probably) has its own set of problems, so I'm open to hearing other ideas.



      Or... why does it completely break the code when the token is expired?



      *I console logged out every catch and then block, but near as I can tell, it's the outer-most catch catches the error with this:




      TokenExpiredError: jwt expired




      Thanks.







      node.js promise jwt






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 14 at 11:14









      zack_falcon

      1,526124176




      1,526124176





























          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53298930%2fnode-jwt-how-can-i-send-a-new-token-when-the-old-one-expires%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53298930%2fnode-jwt-how-can-i-send-a-new-token-when-the-old-one-expires%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

          ComboBox Display Member on multiple fields

          Is it possible to collect Nectar points via Trainline?