jwt-smith
Version:
Enhanced JWT Authentication and Authorization Module
732 lines (718 loc) • 30.9 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
JwtManager: () => JwtManager,
roleBasedAuthenticationMiddleware: () => role_based_authentication_middleware_default,
setDefaultSignOptions: () => setDefaultSignOptions,
setDefaultVerifyOptions: () => setDefaultVerifyOptions,
sign: () => sign,
validateJwtCookieMiddleware: () => auth_cookie_verification_middleware_default,
validateJwtHeaderMiddleware: () => auth_header_verification_middleware_default,
verify: () => verify
});
module.exports = __toCommonJS(src_exports);
// src/lib/core.ts
var import_joi3 = __toESM(require("joi"));
// src/lib/logger.ts
var LOGGER_PREFIX = "[JWT-Smith] ";
var currentLogger = console;
var logSettings = {
setPrefix: true
};
var setLogger = (logger, options) => {
currentLogger = logger;
logSettings = {
...logSettings,
...options || {}
};
};
var getLogger = () => {
return currentLogger;
};
var logFormat = (message) => {
return `${logSettings.setPrefix ? LOGGER_PREFIX : ""}${message}`;
};
var log = (level, message, ...args) => {
const logger = getLogger();
if (logger[level]) {
logger[level](logFormat(message), ...args);
} else {
console.error(logFormat(`Invalid log level: ${level}`));
}
};
// src/lib/signing-token.ts
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
var import_joi = __toESM(require("joi"));
var signTokenOptionsSchema = import_joi.default.object({
algorithm: import_joi.default.string().default("HS256"),
keyid: import_joi.default.string(),
expiresIn: import_joi.default.alternatives().try(import_joi.default.string(), import_joi.default.number()),
notBefore: import_joi.default.alternatives().try(import_joi.default.string(), import_joi.default.number()),
audience: import_joi.default.alternatives().try(import_joi.default.string(), import_joi.default.array().items(import_joi.default.string())),
subject: import_joi.default.string(),
issuer: import_joi.default.string(),
jwtid: import_joi.default.string(),
mutatePayload: import_joi.default.bool(),
noTimestamp: import_joi.default.bool(),
header: import_joi.default.object(),
encoding: import_joi.default.string(),
allowInsecureKeySizes: import_joi.default.bool(),
allowInvalidAsymmetricKeyTypes: import_joi.default.boolean()
});
var secretSchema = import_joi.default.alternatives().try(
import_joi.default.string(),
import_joi.default.binary(),
import_joi.default.object().instance(Buffer),
import_joi.default.object({
key: import_joi.default.alternatives().try(import_joi.default.string(), import_joi.default.binary()),
passphrase: import_joi.default.string()
})
).not("");
var signTokenParamsSchema = import_joi.default.object({
payload: import_joi.default.alternatives().try(import_joi.default.string(), import_joi.default.object(), import_joi.default.binary()).required(),
secret: secretSchema.required(),
options: signTokenOptionsSchema.optional()
});
var defaultSignOptions = {};
var sign = (parameters) => {
return new Promise((resolve, reject) => {
const { error, warning, value } = signTokenParamsSchema.validate(parameters);
if (error) {
reject(logFormat(`Parameter Validation Error: ${error.message}`));
} else if (warning) {
log("warn", "Parameter Validation Warning:", { warning_details: warning });
}
const { payload, secret, options = {} } = value;
const signOptions = { ...defaultSignOptions, ...options };
import_jsonwebtoken.default.sign(payload, secret, signOptions, (err, token) => {
if (err) {
reject(err);
} else {
resolve(token);
}
});
});
};
var setDefaultSignOptions = (options) => {
const { error, warning, value } = signTokenOptionsSchema.validate(options);
if (error) {
throw new Error(logFormat(`Parameter Validation Error: ${error.message}`));
} else if (warning) {
log("warn", "Parameter Validation Warning:", { warning_details: warning });
}
defaultSignOptions = value;
};
// src/lib/verify-token.ts
var import_jsonwebtoken2 = __toESM(require("jsonwebtoken"));
var import_joi2 = __toESM(require("joi"));
var verifyTokenOptionsSchema = import_joi2.default.object({
algorithms: import_joi2.default.array().items(import_joi2.default.string()),
audience: import_joi2.default.alternatives().try(import_joi2.default.string(), import_joi2.default.array().items(import_joi2.default.string())),
clockTimestamp: import_joi2.default.number(),
clockTolerance: import_joi2.default.number(),
complete: import_joi2.default.bool(),
issuer: import_joi2.default.alternatives().try(import_joi2.default.string(), import_joi2.default.array().items(import_joi2.default.string())),
ignoreExpiration: import_joi2.default.boolean(),
ignoreNotBefore: import_joi2.default.boolean(),
jwtid: import_joi2.default.string(),
nonce: import_joi2.default.string(),
subject: import_joi2.default.string(),
maxAge: import_joi2.default.alternatives().try(import_joi2.default.string(), import_joi2.default.number()),
allowInvalidAsymmetricKeyTypes: import_joi2.default.boolean()
});
var secretSchema2 = import_joi2.default.alternatives().try(
import_joi2.default.string().not(""),
import_joi2.default.binary(),
import_joi2.default.object().instance(Buffer),
import_joi2.default.object({
key: import_joi2.default.alternatives().try(import_joi2.default.string(), import_joi2.default.binary()),
passphrase: import_joi2.default.string()
})
);
var verifyTokenParamsSchema = import_joi2.default.object({
token: import_joi2.default.string().not("").required(),
secret: secretSchema2.required(),
options: verifyTokenOptionsSchema.optional()
});
var defaultVerifyOptions = {};
var verify = (parameters) => {
return new Promise((resolve, reject) => {
const { error, warning, value } = verifyTokenParamsSchema.validate(parameters);
if (error) {
reject(logFormat(`Parameter Validation Error: ${error.message}`));
} else if (warning) {
log("warn", "Parameter Validation Warning:", { warning_details: warning });
}
const { token, secret, options = {} } = value;
const verifyOptions = { ...defaultVerifyOptions, options };
import_jsonwebtoken2.default.verify(token, secret, verifyOptions, (err, decoded) => {
if (err) {
reject(err);
} else {
resolve(decoded);
}
});
});
};
var setDefaultVerifyOptions = (options) => {
const { error, warning, value } = verifyTokenOptionsSchema.validate(options);
if (error) {
throw new Error(logFormat(`Parameter Validation Error: ${error.message}`));
} else if (warning) {
log("warn", "Parameter Validation Warning:", { warning_details: warning });
}
defaultVerifyOptions = value;
};
// src/helper/utils.ts
var extractAuthHeaderValue = (header) => {
let tokenValue;
if (header && header.split(" ")[1]) {
tokenValue = header.split(" ")[1];
}
return tokenValue;
};
var appendTokenPayloadToRequest = (req, appendToRequest, decodedTokenPayload) => {
if (Array.isArray(appendToRequest) && appendToRequest?.length > 0 && decodedTokenPayload && typeof decodedTokenPayload !== "string") {
log("debug", `Properties to append to the request: ${appendToRequest}`);
try {
const castedPayload = decodedTokenPayload;
appendToRequest.forEach((item) => {
if (Object.hasOwn(castedPayload, item)) {
req[item] = castedPayload[item];
}
});
} catch (error) {
log("error", "Token payload appending to the request failed!", error);
}
} else if (typeof appendToRequest === "boolean" && typeof decodedTokenPayload === "string") {
log("debug", `Token payload appending to the request: ${decodedTokenPayload}`);
req.tokenPayload = decodedTokenPayload;
}
};
var defaultTokenGenerationHandler = async (refreshTokenPayload) => {
if (process.env.NODE_ENV === "production") {
throw new Error("Token generation handler not implemented.");
} else {
log("warn", "Token generation handler not implemented. Using default handler.");
console.debug({ refreshTokenPayload });
}
return {
token: "new-token",
refreshToken: "new-refresh-token"
};
};
var defaultAuthTokenPayloadVerifier = async (tokenPayload) => {
if (!tokenPayload) {
throw new Error("Empty payload in the auth token.");
}
};
var defaultRefreshTokenPayloadVerifier = async (tokenPayload) => {
const user = tokenPayload?.user;
const userId = user?.id;
if (!userId) {
throw new Error("Refresh token process failed. User ID not found in the refresh payload.");
}
};
var defaultRefreshTokenHolderVerifier = async (tokenHolder, tokenPayload) => {
const user = tokenPayload?.user;
const userId = user?.id || user?.userId;
const tokenHolderId = tokenHolder?.id || tokenHolder?.userId;
return tokenHolderId === userId;
};
var defaultExtractApiVersion = async (req) => {
const version = req.headers["api-version"];
return version ?? req.baseUrl.split("/")[1];
};
// src/lib/core.ts
var publicKey;
var refreshTokenKey;
var middlewareConfigs = {
tokenStorage: void 0,
authHeaderName: "authorization",
appendToRequest: [],
cookieSettings: { accessTokenCookieName: "accessToken", accessCookieOptions: {}, refreshTokenCookieName: void 0 },
authTokenExtractor: extractAuthHeaderValue,
tokenGenerationHandler: defaultTokenGenerationHandler,
refreshTokenPayloadVerifier: defaultRefreshTokenPayloadVerifier,
refreshTokenHolderVerifier: defaultRefreshTokenHolderVerifier,
extractApiVersion: defaultExtractApiVersion
};
var secretSchema3 = import_joi3.default.alternatives().try(
import_joi3.default.string(),
import_joi3.default.binary(),
import_joi3.default.object().instance(Buffer),
import_joi3.default.object({
key: import_joi3.default.alternatives().try(import_joi3.default.string(), import_joi3.default.binary()),
passphrase: import_joi3.default.string()
})
);
var configOptionsSchema = import_joi3.default.object({
logger: import_joi3.default.object().optional(),
publicKey: secretSchema3.optional(),
refreshTokenKey: secretSchema3.optional(),
signOptions: import_joi3.default.object().optional(),
verifyOptions: import_joi3.default.object().optional(),
middlewareConfigs: import_joi3.default.object().optional()
});
var JwtManager = (options) => {
const { error, warning, value } = configOptionsSchema.validate(options);
if (error) {
throw new Error(logFormat(`Parameter Validation Error: ${error.message}`));
} else if (warning) {
log("warn", "Parameter Validation Warning:", { warning_details: warning });
}
if (value.logger) setLogger(value.logger);
if (value.publicKey) publicKey = value.publicKey;
if (value.refreshTokenKey) refreshTokenKey = value.refreshTokenKey;
if (value.signOptions) setDefaultSignOptions(value.signOptions);
if (value.verifyOptions) setDefaultVerifyOptions(value.verifyOptions);
if (value.middlewareConfigs) middlewareConfigs = { ...middlewareConfigs, ...value.middlewareConfigs };
};
// src/module/token-storage.ts
var DefaultTokenStorage = class {
tokens = /* @__PURE__ */ new Map();
defectedTokens = /* @__PURE__ */ new Map();
async saveOrUpdateToken(userId, tokenOrRefreshToken, token) {
const existingData = this.tokens.get(userId) || { refreshTokens: [], tokens: [] };
let update = { refreshTokens: [] };
update = {
...existingData,
refreshTokens: [...existingData.refreshTokens || [], tokenOrRefreshToken]
};
if (token) {
update = {
...update,
tokens: [...existingData.tokens || [], token]
};
}
this.tokens.set(userId, update);
}
async getRefreshTokenHolder(refreshToken) {
let holder = null;
this.tokens.forEach((data, userId) => {
if (data.refreshTokens?.includes(refreshToken)) {
holder = { id: userId, ...this.tokens.get(userId) };
return;
}
});
return holder;
}
async getRefreshToken(userId) {
return this.tokens.get(userId)?.refreshTokens || null;
}
async deleteToken(userId) {
this.tokens.delete(userId);
}
async getToken(userId) {
return this.tokens.get(userId)?.tokens || null;
}
async blackListRefreshToken(token, relatedData) {
this.defectedTokens.set(token, relatedData || {});
}
async checkBlackListedRefreshToken(token) {
return this.defectedTokens.get(token);
}
};
// src/module/refresh-token-handler.ts
var import_jsonwebtoken3 = require("jsonwebtoken");
var TokenHandler = class {
refreshTokenStorage;
tokenGenerationHandler;
authTokenPayloadVerifier;
refreshTokenPayloadVerifier;
refreshTokenHolderVerifier;
constructor(options) {
this.refreshTokenStorage = options.refreshTokenStorage || new DefaultTokenStorage();
this.tokenGenerationHandler = options.tokenGenerationHandler;
this.authTokenPayloadVerifier = options.authTokenPayloadVerifier || defaultAuthTokenPayloadVerifier;
this.refreshTokenPayloadVerifier = options.refreshTokenPayloadVerifier || defaultRefreshTokenPayloadVerifier;
this.refreshTokenHolderVerifier = options.refreshTokenHolderVerifier || defaultRefreshTokenHolderVerifier;
if (!options.refreshTokenStorage) {
const logType = process.env.NODE_ENV === "production" ? "error" : "warn";
log(logType, "[TokenHandler]: Using default in-memory token storage. This is not recommended for production.");
}
}
async validateOrRefreshAuthToken(authToken, refreshToken) {
let decodedToken;
let token = authToken;
let nextRefreshToken = refreshToken;
await this.validateAuthToken(authToken).then((tokenPayload) => {
decodedToken = tokenPayload;
}).catch(async (error) => {
if (error instanceof import_jsonwebtoken3.TokenExpiredError && refreshToken) {
const response = await this.rotateRefreshToken(refreshToken, authToken);
token = response.token;
nextRefreshToken = response.refreshToken;
decodedToken = await verify({
token,
secret: publicKey
});
} else {
log("info", "Refresh token not found.");
throw error;
}
});
return { decodedToken, nextRefreshToken, token };
}
async validateAuthToken(authToken) {
const tokenPayload = await verify({
token: authToken,
secret: publicKey
});
await this.authTokenPayloadVerifier(tokenPayload);
log("info", "Auth token validation complete!");
return tokenPayload;
}
async rotateRefreshToken(refreshToken, token) {
try {
const isBlackListed = await this.refreshTokenStorage.checkBlackListedRefreshToken(refreshToken);
log("debug", "Checking if the refresh token is blacklisted.");
if (isBlackListed) {
log("error", "Blacklisted refresh token received!", { refreshToken });
throw new Error("Blacklisted refresh token found!");
}
const decodedTokenPayload = await verify({
token: refreshToken,
secret: refreshTokenKey || publicKey
});
log("debug", "Decoded the refresh token payload.");
if (!decodedTokenPayload) {
throw new Error("Refresh token payload is undefined!");
}
await this.refreshTokenPayloadVerifier(decodedTokenPayload);
log("debug", "Refresh token payload verification complete.");
const tokenHolder = await this.refreshTokenStorage.getRefreshTokenHolder(refreshToken);
log("debug", "Retrieved the refresh token holder.");
if (!tokenHolder) {
throw new Error("Could not find a matching token holder for the refresh token.");
}
const isHolderVerified = await this.refreshTokenHolderVerifier(tokenHolder, decodedTokenPayload);
log("debug", "Refresh token holder verification complete.");
if (!isHolderVerified) {
await this.refreshTokenStorage.blackListRefreshToken(refreshToken);
throw new Error("Refresh token holder verification failed.");
}
const response = await this.tokenGenerationHandler(decodedTokenPayload, tokenHolder);
log("debug", "Generated new tokens.");
const userId = tokenHolder.id || (typeof decodedTokenPayload !== "string" && "user" in decodedTokenPayload ? decodedTokenPayload.user?.id : void 0);
await this.refreshTokenStorage.saveOrUpdateToken(userId, response.refreshToken, response.token);
log("debug", "Saved the new tokens.");
return response;
} catch (error) {
await this.cleanupInvalidRefreshToken(refreshToken, token);
throw error;
}
}
async cleanupInvalidRefreshToken(refreshToken, token) {
const tokenHolder = await this.refreshTokenStorage.getRefreshTokenHolder(refreshToken);
if (tokenHolder && Object.hasOwn(tokenHolder, "id")) {
const userId = tokenHolder.id;
await this.refreshTokenStorage.deleteToken(userId, token, refreshToken);
}
}
};
// src/middleware/auth-header-verification.middleware.ts
var validateJwtHeaderMiddleware = async (req, res, next) => {
try {
const {
appendToRequest = [],
authHeaderName,
refreshTokenHeaderName,
authTokenExtractor,
tokenGenerationHandler,
cookieSettings = {},
authTokenPayloadVerifier,
refreshTokenPayloadVerifier,
refreshTokenHolderVerifier,
tokenStorage
} = middlewareConfigs;
let authHeader = req.headers[authHeaderName ?? ""];
log("debug", "Auth header and middleware configurations extracted.");
if (Array.isArray(authHeader)) authHeader = authHeader.join("__");
log("debug", `Auth header: ${authHeader}`);
if (!authHeader || !authHeader.startsWith("Bearer ")) {
throw new Error("Valid auth header not found");
}
if (authTokenExtractor) {
log("debug", "Auth token extractor method found.");
const tokenValue = authTokenExtractor(authHeader);
log("debug", `Auth token value: ${tokenValue}`);
if (!tokenValue) {
throw new Error("Auth token not found");
}
let refreshToken = req.cookies && cookieSettings.refreshTokenCookieName ? req.cookies[cookieSettings.refreshTokenCookieName] : void 0;
if (!refreshToken && refreshTokenHeaderName) {
refreshToken = req.headers[refreshTokenHeaderName];
}
log("debug", "Refresh token extracted.");
const refreshTokenHandler = new TokenHandler({
refreshTokenStorage: tokenStorage,
tokenGenerationHandler,
authTokenPayloadVerifier,
refreshTokenPayloadVerifier,
refreshTokenHolderVerifier
});
log("debug", "Token handler created.");
log("debug", `Auth token: ${tokenValue} | Refresh token: ${refreshToken}`);
const { decodedToken, nextRefreshToken, token } = await refreshTokenHandler.validateOrRefreshAuthToken(
tokenValue,
refreshToken
);
log("debug", "Token handler validated or refreshed the auth token.");
if (!decodedToken) {
throw new Error("Auth cookie payload is undefined!");
}
appendTokenPayloadToRequest(req, appendToRequest, decodedToken);
log("debug", "Token payload appended to the request object.");
res.setHeader(authHeaderName ?? "authorization", token);
if (cookieSettings.refreshTokenCookieName && nextRefreshToken) {
log("debug", "New refresh token set in the cookie.");
res.cookie(cookieSettings.refreshTokenCookieName, nextRefreshToken, cookieSettings.refreshCookieOptions || {});
} else if (refreshTokenHeaderName && nextRefreshToken) {
log("debug", "New refresh token set in the header.");
res.setHeader(refreshTokenHeaderName, nextRefreshToken);
}
log("debug", "Next middleware called.");
return next();
} else {
throw new Error("Token value extractor method not found");
}
} catch (error) {
log("error", "Error occurred while authenticating the JST token.", error);
const errorMessage = error instanceof Error ? error.message : "Unknown error";
res.status(401).json({ message: "Unauthorized", error: errorMessage });
}
};
var auth_header_verification_middleware_default = validateJwtHeaderMiddleware;
// src/middleware/role-based-authentication.middleware.ts
var import_promises = __toESM(require("fs/promises"));
var import_joi4 = __toESM(require("joi"));
// src/helper/constants.ts
var RolePermissionConfigFilePath = "./.auth-permissions.json";
// src/middleware/role-based-authentication.middleware.ts
var permissionSchema = import_joi4.default.object({
roles: import_joi4.default.array().items(import_joi4.default.string().required()).required(),
actions: import_joi4.default.array().items(import_joi4.default.string().required()).required()
});
var endpointSchema = import_joi4.default.object({
path: import_joi4.default.string().required(),
methods: import_joi4.default.array().items(import_joi4.default.string().valid("GET", "POST", "PUT", "PATCH", "DELETE")).required(),
permissions: import_joi4.default.array().items(permissionSchema).required()
});
var groupSchema = import_joi4.default.object({
basePath: import_joi4.default.string().required(),
permissions: import_joi4.default.array().items(permissionSchema).required(),
endpoints: import_joi4.default.array().items(endpointSchema).required()
});
var commonRolesSchema = import_joi4.default.object({
name: import_joi4.default.string().required(),
permissions: import_joi4.default.array().items(import_joi4.default.string().required()).required()
});
var permissionsConfigSchema = import_joi4.default.object({
versioned: import_joi4.default.boolean().optional(),
activeVersions: import_joi4.default.array().items(import_joi4.default.string().required()).optional(),
common: import_joi4.default.object({
roles: import_joi4.default.array().items(commonRolesSchema).required()
}).optional(),
groups: import_joi4.default.object().pattern(import_joi4.default.string(), groupSchema).optional(),
endpoints: import_joi4.default.array().items(endpointSchema).optional()
});
var getPermissionConfigs = async () => {
await import_promises.default.stat(RolePermissionConfigFilePath).catch((e) => {
log("error", "Auth permissions configuration file could not found");
throw e;
});
return JSON.parse(await import_promises.default.readFile(RolePermissionConfigFilePath, "utf-8"));
};
var roleBasedAuthenticationMiddleware = (requiredAction) => {
return async (req, res, next) => {
const { extractApiVersion } = middlewareConfigs;
const { user, role } = req;
const userRole = user && Object.hasOwn(user, "role") ? user.role : role;
const endpointPath = req.baseUrl;
const method = req.method;
let requestVersion = void 0;
let versionValidationError = void 0;
log("debug", "Role-based authentication middleware invoked.");
if (extractApiVersion) {
const version = await extractApiVersion(req);
if (version) {
requestVersion = version;
}
}
log("debug", "Role-based authentication middleware configurations extracted.");
log(
"debug",
`User role: ${userRole} | Required action: ${requiredAction} | Endpoint: ${endpointPath} | Method: ${method}`
);
log("debug", `API version extracted from the request: ${requestVersion}`);
if (!userRole) {
res.status(403).json({ error: "Access denied. Role not found." });
} else {
const permissionsConfig = await getPermissionConfigs();
log("debug", "Auth permissions configuration file loaded.");
const { error } = permissionsConfigSchema.validate(permissionsConfig);
log("debug", "Auth permissions configuration file validated.");
if (error) {
log("error", "Auth Permissions config file's validation failed.", error);
throw error;
}
if (!permissionsConfig.common && !permissionsConfig.groups && !permissionsConfig.endpoints) {
log("error", "At least one permission set should be in the configs.");
throw new Error("Permission configurations is empty.");
}
if (permissionsConfig.versioned) {
if (!requestVersion) {
versionValidationError = "Access denied. Insufficient permissions.";
}
if (requestVersion && !permissionsConfig.activeVersions?.includes(requestVersion)) {
versionValidationError = "Unsupported API version.";
}
}
log("debug", "Permission configurations validated.");
if (versionValidationError) {
log("error", versionValidationError);
res.status(400).json({ error: versionValidationError });
} else {
log("debug", "Permission configurations validating...");
if (permissionsConfig.endpoints) {
const standaloneEndpoint = permissionsConfig.endpoints.find(
(ep) => ep.path === endpointPath && ep.methods.includes(method)
);
if (standaloneEndpoint) {
if (checkPermissions(userRole, requiredAction, [], standaloneEndpoint.permissions)) {
return next();
}
}
}
if (permissionsConfig.groups) {
const groups = Object.values(permissionsConfig.groups);
const matchedGroup = groups.find(
(group) => endpointPath.startsWith(group.basePath) && group.endpoints.some((ep) => ep.path === endpointPath)
);
if (matchedGroup) {
const groupPermissions = matchedGroup.permissions || [];
const endpointPermissions = matchedGroup.endpoints.find(
(ep) => ep.path === endpointPath && ep.methods.includes(method)
)?.permissions || [];
if (checkPermissions(userRole, requiredAction, groupPermissions, endpointPermissions)) {
return next();
}
}
}
if (permissionsConfig.common) {
const commonRoles = permissionsConfig.common.roles || [];
const commonRole = commonRoles.find((role2) => role2.name === userRole);
if (commonRole && commonRole.permissions.includes("*:*")) {
return next();
}
}
res.status(403).json({ error: "Access denied. Insufficient permissions." });
}
}
};
};
function checkPermissions(userRole, requiredAction, groupPermissions, endpointPermissions) {
const combinedPermissions = [...groupPermissions, ...endpointPermissions];
return combinedPermissions.some((permission) => {
if (permission.roles.includes(userRole)) {
return permission.actions.includes(requiredAction) || permission.actions.includes("*:*");
}
return false;
});
}
var role_based_authentication_middleware_default = roleBasedAuthenticationMiddleware;
// src/middleware/auth-cookie-verification.middleware.ts
var validateJwtCookieMiddleware = async (req, res, next) => {
try {
const {
appendToRequest = [],
tokenGenerationHandler,
cookieSettings = {},
authTokenPayloadVerifier,
refreshTokenPayloadVerifier,
refreshTokenHolderVerifier,
tokenStorage
} = middlewareConfigs;
const accessToken = req.cookies && cookieSettings.accessTokenCookieName ? req.cookies[cookieSettings.accessTokenCookieName] : void 0;
const refreshToken = req.cookies && cookieSettings.refreshTokenCookieName ? req.cookies[cookieSettings.refreshTokenCookieName] : void 0;
if (!accessToken && !refreshToken) {
throw new Error("Auth cookie not found!");
}
log("debug", "Auth cookie and middleware configurations extracted.");
log("debug", `Access token: ${accessToken} | Refresh token: ${refreshToken}`);
const refreshTokenHandler = new TokenHandler({
refreshTokenStorage: tokenStorage,
tokenGenerationHandler,
authTokenPayloadVerifier,
refreshTokenPayloadVerifier,
refreshTokenHolderVerifier
});
log("debug", "Token handler created.");
const { decodedToken, nextRefreshToken, token } = await refreshTokenHandler.validateOrRefreshAuthToken(
accessToken,
refreshToken
);
log("debug", "Token handler validated or refreshed the auth token.");
if (!decodedToken) {
throw new Error("Auth cookie payload is undefined!");
}
appendTokenPayloadToRequest(req, appendToRequest, decodedToken);
log("debug", "Token payload appended to the request object.");
if (cookieSettings.accessTokenCookieName) {
log("debug", "New access token set in the cookie.");
res.cookie(cookieSettings.accessTokenCookieName, token, cookieSettings.accessCookieOptions || {});
}
if (cookieSettings.refreshTokenCookieName && nextRefreshToken) {
log("debug", "New refresh token set in the cookie.");
res.cookie(cookieSettings.refreshTokenCookieName, nextRefreshToken, cookieSettings.refreshCookieOptions || {});
}
log("debug", "Token handler completed successfully.");
next();
} catch (error) {
log("error", "Error occurred while authenticating the JST token.", error);
const errorMessage = error instanceof Error ? error.message : "Unknown error";
res.status(401).json({ message: "Unauthorized", error: errorMessage });
}
};
var auth_cookie_verification_middleware_default = validateJwtCookieMiddleware;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
JwtManager,
roleBasedAuthenticationMiddleware,
setDefaultSignOptions,
setDefaultVerifyOptions,
sign,
validateJwtCookieMiddleware,
validateJwtHeaderMiddleware,
verify
});
//# sourceMappingURL=index.js.map
;