diff --git a/src/.env.sample b/src/.env.sample index 465cb9c04..3b0b5c668 100644 --- a/src/.env.sample +++ b/src/.env.sample @@ -172,6 +172,12 @@ ADMIN_TOKEN_HEADER_NAME='admin-auth-token' # The header name used to pass the organization ID in HTTP requests. This helps identify the organization associated with the request. ORG_ID_HEADER_NAME='organization-id' +# The header name used to pass the organization code in HTTP requests (used by admins to operate in a specific org context). +ORG_CODE_HEADER_NAME='x-org-code' + +# The header name used to pass the tenant code in HTTP requests (used by admins to operate in a specific tenant context). +TENANT_CODE_HEADER_NAME='x-tenant-code' + # Flag to enable/disable chat chapabilities ENABLE_CHAT=true diff --git a/src/constants/common.js b/src/constants/common.js index 6e935e887..ae6b4ac2a 100644 --- a/src/constants/common.js +++ b/src/constants/common.js @@ -317,4 +317,6 @@ module.exports = { ASCENDING: 'ASC', DESCENDING: 'DESC', }, + ORG_CODE_HEADER: process.env.ORG_CODE_HEADER_NAME.toLowerCase(), + TENANT_CODE_HEADER: process.env.TENANT_CODE_HEADER_NAME.toLowerCase(), } diff --git a/src/envVariables.js b/src/envVariables.js index 16d17b22b..486f6ef2c 100644 --- a/src/envVariables.js +++ b/src/envVariables.js @@ -46,6 +46,16 @@ let enviromentVariables = { optional: true, default: 'organization-id', }, + ORG_CODE_HEADER_NAME: { + message: 'Required organization 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', + }, IS_AUTH_TOKEN_BEARER: { message: 'Required specification: If auth token is bearer or not', optional: true, diff --git a/src/middlewares/authenticator.js b/src/middlewares/authenticator.js index cfebc1e6a..9acc291cc 100644 --- a/src/middlewares/authenticator.js +++ b/src/middlewares/authenticator.js @@ -123,6 +123,35 @@ module.exports = async function (req, res, next) { } } + // Handle organization/tenant override for admin and org admin (mirrors user service logic) + const isAdminUser = + req.decodedToken.roles && req.decodedToken.roles.some((role) => role.title === common.ADMIN_ROLE) + const isOrgAdmin = + req.decodedToken.roles && req.decodedToken.roles.some((role) => role.title === common.ORG_ADMIN_ROLE) + + if (isAdminUser || isOrgAdmin) { + const orgCode = (req.headers[common.ORG_CODE_HEADER] || '').trim() + const tenantCode = (req.headers[common.TENANT_CODE_HEADER] || '').trim() + + if (isOrgAdmin && !isAdminUser) { + // Org admin: can only override organization_code, NOT tenant_code (security) + if (orgCode) req.decodedToken.organization_code = orgCode + } else if (isAdminUser) { + // Super admin: can override both, but must supply both together + if (orgCode || tenantCode) { + if (!orgCode || !tenantCode) { + throw responses.failureResponse({ + message: 'BOTH_X_ORG_CODE_AND_X_TENANT_CODE_HEADERS_REQUIRED', + statusCode: httpStatusCode.bad_request, + responseCode: 'CLIENT_ERROR', + }) + } + req.decodedToken.tenant_code = tenantCode + req.decodedToken.organization_code = orgCode + } + } + } + req.decodedToken.id = typeof req.decodedToken?.id === 'number' ? req.decodedToken?.id?.toString() : req.decodedToken?.id req.decodedToken.organization_id =