11const authService = require ( "../services/authService" ) ;
22const dataAccess = require ( "../services/dataAccessLayer" ) ;
3+ const logger = require ( "../utils/logger" ) ;
34
45/**
5- * Middleware to check if the authenticated user has restricted permissions .
6+ * Middleware to check if the user is restricted or in an impersonation session .
67 *
7- * - If the user is impersonating, restrict to only ` GET` and `PATCH` requests with `action=STOP` .
8- * - If the user has a ` restricted` role, disallow all non- GET requests.
8+ * - If the user is impersonating, only GET requests and the STOP impersonation route are allowed .
9+ * - If the user is restricted (based on roles), only GET requests are permitted .
910 *
10- * This middleware must be invoked after successful authentication.
11- *
12- * @param {Object } req - Express request object. Expects `userData` and `isImpersonating` to be set.
13- * @param {Object } res - Express response object.
14- * @param {Function } next - Express next middleware function.
15- * @returns {Object| void } Responds with `403 Forbidden` if action is not permitted; otherwise calls `next()`.
11+ * @async
12+ * @function checkRestricted
13+ * @param {import('express').Request } req - Express request object
14+ * @param {import('express').Response } res - Express response object
15+ * @param {Function } next - Express next middleware function
16+ * @returns {void }
1617 */
1718const checkRestricted = async ( req , res , next ) => {
1819 const { roles } = req . userData ;
@@ -25,7 +26,7 @@ const checkRestricted = async (req, res, next) => {
2526 req . query . action === "STOP" ;
2627
2728 if ( req . method !== "GET" && ! isStopImpersonationRoute ) {
28- return res . boom . forbidden ( "You are not allowed for this operation at the moment " ) ;
29+ return res . boom . forbidden ( "Only viewing is permitted during impersonation " ) ;
2930 }
3031 }
3132
@@ -37,39 +38,38 @@ const checkRestricted = async (req, res, next) => {
3738} ;
3839
3940/**
40- * Authentication Middleware
41- *
42- * 1. Verifies the user's JWT (from cookie or Bearer header in non-production).
43- * 2. If the token is valid, attaches user info to `req.userData`.
44- * 3. If impersonation is active, uses the impersonated user for `req.userData`.
45- * 4. If the JWT is expired but within `refreshTtl`, issues a new token and continues.
46- * 5. Applies role-based restrictions via `checkRestricted()`.
47- *
48- * @todo Add test cases to validate JWT refresh logic by simulating token expiry and TTL.
41+ * Authentication middleware that:
42+ * 1. Verifies JWT token from cookies (or headers in non-production).
43+ * 2. Handles impersonation if applicable.
44+ * 3. Refreshes token if it's expired but still within the refresh TTL window.
45+ * 4. Attaches user data to `req.userData` for downstream use.
4946 *
50- * @param {Object } req - Express request object.
51- * @param {Object } res - Express response object.
52- * @param {Function } next - Express next middleware function.
53- * @returns {Object|void } - Returns `401 Unauthorized` if the user is unauthenticated; otherwise continues to `checkRestricted`.
47+ * @async
48+ * @function
49+ * @param {import('express').Request } req - Express request object
50+ * @param {import('express').Response } res - Express response object
51+ * @param {Function } next - Express next middleware function
52+ * @returns {Promise<void> } - Calls `next()` on successful authentication or returns an error response.
5453 */
5554module . exports = async ( req , res , next ) => {
5655 try {
5756 let token = req . cookies [ config . get ( "userToken.cookieName" ) ] ;
5857
59- // Allow Bearer token in non-production (e.g., for Swagger UI)
58+ /**
59+ * Enable Bearer Token authentication for NON-PRODUCTION environments.
60+ * Useful for Swagger or manual testing where cookies are not easily managed.
61+ */
6062 if ( process . env . NODE_ENV !== "production" && ! token ) {
6163 token = req . headers . authorization ?. split ( " " ) [ 1 ] ;
6264 }
6365
6466 const { userId, impersonatedUserId } = authService . verifyAuthToken ( token ) ;
67+ // `req.isImpersonating` keeps track of the impersonation session
6568 req . isImpersonating = Boolean ( impersonatedUserId ) ;
6669
67- let userData ;
68- if ( impersonatedUserId ) {
69- userData = await dataAccess . retrieveUsers ( { id : impersonatedUserId } ) ;
70- } else {
71- userData = await dataAccess . retrieveUsers ( { id : userId } ) ;
72- }
70+ const userData = impersonatedUserId
71+ ? await dataAccess . retrieveUsers ( { id : impersonatedUserId } )
72+ : await dataAccess . retrieveUsers ( { id : userId } ) ;
7373
7474 req . userData = userData . user ;
7575 return checkRestricted ( req , res , next ) ;
@@ -83,7 +83,7 @@ module.exports = async (req, res, next) => {
8383 const newToken = authService . generateAuthToken ( { userId } ) ;
8484 const rdsUiUrl = new URL ( config . get ( "services.rdsUi.baseUrl" ) ) ;
8585
86- // Refresh token if within allowed refresh window
86+ // add new JWT to the response if it satisfies the refreshTtl time
8787 if ( Math . floor ( Date . now ( ) / 1000 ) - iat <= refreshTtl ) {
8888 res . cookie ( config . get ( "userToken.cookieName" ) , newToken , {
8989 domain : rdsUiUrl . hostname ,
@@ -93,13 +93,13 @@ module.exports = async (req, res, next) => {
9393 sameSite : "lax" ,
9494 } ) ;
9595
96- req . userData = await dataAccess . retrieveUsers ( { id : userId } ) ;
96+ const userData = await dataAccess . retrieveUsers ( { id : userId } ) ;
97+ req . userData = userData . user ;
98+
9799 return checkRestricted ( req , res , next ) ;
98- } else {
99- return res . boom . unauthorized ( "Unauthenticated User" ) ;
100100 }
101- } else {
102101 return res . boom . unauthorized ( "Unauthenticated User" ) ;
103102 }
103+ return res . boom . unauthorized ( "Unauthenticated User" ) ;
104104 }
105105} ;
0 commit comments