From 2b1d7c07a994d6373f2054c772977d88342e6d0a Mon Sep 17 00:00:00 2001 From: Nevil Mathew Date: Thu, 9 Oct 2025 20:01:30 +0530 Subject: [PATCH 1/3] feat(auth): allow admin role to override tenant and org --- src/middlewares/authenticator.js | 55 +++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/src/middlewares/authenticator.js b/src/middlewares/authenticator.js index 5ce40ccc9..ab4a494d0 100644 --- a/src/middlewares/authenticator.js +++ b/src/middlewares/authenticator.js @@ -10,7 +10,7 @@ const jwt = require('jsonwebtoken') const httpStatusCode = require('@generics/http-status') const common = require('@constants/common') const userQueries = require('@database/queries/users') -const roleQueries = require('@database/queries/user-role') + const rolePermissionMappingQueries = require('@database/queries/role-permission-mapping') const { Op } = require('sequelize') const responses = require('@helpers/responses') @@ -159,6 +159,7 @@ module.exports = async function (req, res, next) { token = extractedToken.trim() } else token = authHeader.trim() + let decodedToken let org try { decodedToken = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET) @@ -210,10 +211,56 @@ module.exports = async function (req, res, next) { let isAdmin = false if (decodedToken.data.roles) { isAdmin = decodedToken.data.roles.some((role) => role.title == common.ADMIN_ROLE) - if (isAdmin) { - req.decodedToken = decodedToken.data - return next() + } + + if (isAdmin) { + // For admin users, allow overriding tenant_code, organization_id, and organization_code via headers + // Header names are configurable via environment variables with sensible defaults + const orgIdHeaderName = process.env.ORG_ID_HEADER_NAME + const orgCodeHeaderName = process.env.ORG_CODE_HEADER_NAME + const tenantCodeHeaderName = process.env.TENANT_CODE_HEADER_NAME + + // Extract and sanitize header values (trim whitespace, case-insensitive header lookup) + const orgId = (req.headers[orgIdHeaderName.toLowerCase()] || '').trim() + const orgCode = (req.headers[orgCodeHeaderName.toLowerCase()] || '').trim() + const tenantCode = (req.headers[tenantCodeHeaderName.toLowerCase()] || '').trim() + + // If any override header is provided (non-empty after trim), all three must be present and non-empty + const hasAnyOverrideHeader = orgId || orgCode || tenantCode + if (hasAnyOverrideHeader) { + if (!orgId || !orgCode || !tenantCode) { + throw responses.failureResponse({ + message: { + key: 'ADD_ORG_HEADER', + interpolation: { + orgIdHeader: orgIdHeaderName, + orgCodeHeader: orgCodeHeaderName, + tenantCodeHeader: tenantCodeHeaderName, + }, + }, + statusCode: httpStatusCode.bad_request, + responseCode: 'CLIENT_ERROR', + }) + } + + // Validate orgId is a valid positive integer + const parsedOrgId = parseInt(orgId, 10) + if (isNaN(parsedOrgId) || parsedOrgId <= 0) { + throw responses.failureResponse({ + message: 'INVALID_ORG_ID', + statusCode: httpStatusCode.bad_request, + responseCode: 'CLIENT_ERROR', + }) + } + + // Override the values from the token with sanitized header values + decodedToken.data.tenant_code = tenantCode + decodedToken.data.organization_id = orgId + decodedToken.data.organization_code = orgCode } + + req.decodedToken = decodedToken.data + //return next() } if (roleValidation) { From 738816541e2022a5aafef770de3c0af177b804b3 Mon Sep 17 00:00:00 2001 From: Nevil Mathew Date: Thu, 9 Oct 2025 20:01:50 +0530 Subject: [PATCH 2/3] feat(env): add optional headers for ORG_ID, ORG_CODE, and TENANT_CODE --- src/envVariables.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/envVariables.js b/src/envVariables.js index e640e1c0a..8be773a91 100644 --- a/src/envVariables.js +++ b/src/envVariables.js @@ -458,6 +458,21 @@ let enviromentVariables = { value: 'true', }, }, + ORG_ID_HEADER_NAME: { + message: 'Required ORG_ID_HEADER_NAME', + optional: true, + default: 'X-Org-Id', + }, + ORG_CODE_HEADER_NAME: { + message: 'Required ORG_CODE_HEADER_NAME', + optional: true, + default: 'X-Org-Code', + }, + TENANT_CODE_HEADER_NAME: { + message: 'Required TENANT_CODE_HEADER_NAME', + optional: true, + default: 'X-Tenant-Code', + }, } let success = true From 490a558b76f72d9427fb9e965c8f630add1de098 Mon Sep 17 00:00:00 2001 From: Nevil Mathew Date: Thu, 9 Oct 2025 20:02:39 +0530 Subject: [PATCH 3/3] feat(locales): add organization header messages and validation for org ID --- src/locales/en.json | 4 +++- src/middlewares/authenticator.js | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/locales/en.json b/src/locales/en.json index 64d5f726a..0aca71153 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -182,5 +182,7 @@ "REG_CODE_ERROR": "registration_code is not valid or unique.", "INVALID_REG_CODE_ERROR": "registration_codes {{errorMessage}}. Invalid Code(s) : {{errorValues}}", "UNIQUE_CONSTRAINT_ERROR": "{{fields}} is Invalid.", - "USER_PROFILE_FETCHED_SUCCESSFULLY": "User profile fetched successfully!" + "USER_PROFILE_FETCHED_SUCCESSFULLY": "User profile fetched successfully!", + "ADD_ORG_HEADER": "Please provide all required organization headers: {orgIdHeader}, {orgCodeHeader}, and {tenantCodeHeader} for admin override.", + "INVALID_ORG_ID": "Organization ID must be a valid positive integer." } diff --git a/src/middlewares/authenticator.js b/src/middlewares/authenticator.js index ab4a494d0..cd0a95024 100644 --- a/src/middlewares/authenticator.js +++ b/src/middlewares/authenticator.js @@ -260,7 +260,6 @@ module.exports = async function (req, res, next) { } req.decodedToken = decodedToken.data - //return next() } if (roleValidation) {