From 043698e5358c85f2461e4c33bd179cce7c26cffb Mon Sep 17 00:00:00 2001 From: Rushi Gandhi Date: Thu, 17 Oct 2024 17:01:36 +0530 Subject: [PATCH] add endpoint to refresh auth token --- Server/controllers/authController.js | 63 ++++++++++++++++++++++++++++ Server/routes/authRoute.js | 2 + Server/utils/messages.js | 1 + 3 files changed, 66 insertions(+) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 4ce5a0e2b..a9272e7c0 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -173,6 +173,68 @@ const loginUser = async (req, res, next) => { } }; +/** + * Generates new auth token if the refresh token is valid + * @function + * @param {Express.Request} req - The Express request object. + * @property {Object} req.headers - The parameter of the request. + * @param {Express.Response} res - The Express response object. + * @param {function} next - The next middleware function. + * @returns {Object} The response object with a success status, a message indicating new auth token is generated. + * @throws {Error} If there is an error during the process such as any of the token is not received + */ +const refreshAuthToken = (req, res, next) => { + try { + // check for refreshToken + const refreshToken = req.headers["x-refresh-token"]; + + if (!refreshToken) { + // No refresh token provided + const error = new Error(errorMessages.NO_REFRESH_TOKEN); + error.status = 401; + error.service = SERVICE_NAME; + error.method = "handleExpiredJwtToken"; + return next(error); + } + + // Verify refresh token + const { refreshTokenSecret } = req.settingsService.getSettings(); + jwt.verify(refreshToken, refreshTokenSecret, (refreshErr, refreshDecoded) => { + if (refreshErr) { + // Invalid or expired refresh token, trigger logout + const errorMessage = + refreshErr.name === "TokenExpiredError" + ? errorMessages.EXPIRED_REFRESH_TOKEN + : errorMessages.INVALID_REFRESH_TOKEN; + const error = new Error(errorMessage); + error.status = 401; + error.service = SERVICE_NAME; + return next(error); + } + }); + + // Refresh token is valid and unexpired, generate new access token + const oldAuthToken = getTokenFromHeaders(req.headers); + const { jwtSecret } = req.settingsService.getSettings(); + + const payloadData = jwt.verify(oldAuthToken, jwtSecret, { ignoreExpiration: true }); + // delete old token related data + delete payloadData.iat; + delete payloadData.exp; + + const newAuthToken = issueToken(payloadData, tokenType.ACCESS_TOKEN, req.settingsService.getSettings()); + + return res.status(200).json({ + success: true, + msg: successMessages.AUTH_TOKEN_REFRESHED, + data: { user: payloadData, token: newAuthToken, refreshToken: refreshToken }, + }); + } catch (error) { + next(handleError(error, SERVICE_NAME, "refreshAuthToken")); + } +}; + + /** * Edits a user's information. If the user wants to change their password, the current password is checked before updating to the new password. * @async @@ -455,6 +517,7 @@ export { issueToken, registerUser, loginUser, + refreshAuthToken, editUser, checkSuperadminExists, requestRecovery, diff --git a/Server/routes/authRoute.js b/Server/routes/authRoute.js index 11e371654..e19f855db 100644 --- a/Server/routes/authRoute.js +++ b/Server/routes/authRoute.js @@ -11,6 +11,7 @@ const upload = multer(); import { registerUser, loginUser, + refreshAuthToken, editUser, requestRecovery, validateRecovery, @@ -23,6 +24,7 @@ import { //Auth routes router.post("/register", upload.single("profileImage"), registerUser); router.post("/login", loginUser); +router.post("/refresh", refreshAuthToken); router.put("/user/:userId", upload.single("profileImage"), verifyJWT, editUser); router.get("/users/superadmin", checkSuperadminExists); router.get("/users", verifyJWT, isAllowed(["admin", "superadmin"]), getAllUsers); diff --git a/Server/utils/messages.js b/Server/utils/messages.js index f7255af1f..159ed5b30 100644 --- a/Server/utils/messages.js +++ b/Server/utils/messages.js @@ -75,6 +75,7 @@ const successMessages = { AUTH_RESET_PASSWORD: "Password reset successfully", AUTH_ADMIN_CHECK: "Admin check completed successfully", AUTH_DELETE_USER: "User deleted successfully", + AUTH_TOKEN_REFRESHED: "Auth token is refreshed", // Check Controller CHECK_CREATE: "Check created successfully",