npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@keeex/utils-express

v4.2.7

Published

Shared code for express servers

Downloads

5

Readme

Utility functions for express

Bugs Code Smells Maintainability Rating Security Rating Vulnerabilities Technical Debt Coverage

Some tools for express. For now there's a handler for promise-based requests and an authentication middleware.

For developers

When working on this library, run npm run setup to prepare generated files.

Promise-based request

Express does not handle promises. This library promise a helper to handle requests as promises.

Handling a request is done in two parts:

  • handling the request (requestHandler)
  • sending the reply (responseHandler)

The request handling is done by writing a requestHandler taking req and res as parameters. These handlers can return anything; that return value will be handled by a responseHandler. You write as many requestHandler as type of requests.

The responseHandler can be reused for multiple requests, and take as parameter data, req, res, next and extraData. data is the result of the requestHandler, and extraData are the value passed to the caller.

First you can create multiple "middlewares" that take the responseHandler as parameter, and these can then be used with requestHandler to process requests.

Both the responseHandler and the requestHandler can return promises.

Example:

import express from "express";
import {createAsyncHandler} from "@keeex/utils-express/lib/promise.js";

const testDataFunc = () => new Promise(resolve => {
  const startTime = Date.now();
  setTimeout(() => {
    resolve({startTime, replyTime: Date.now()});
  }, 1000);
});

const responseHandler = (data, req, res, next) => {
  if (data === "failure") next(new Error("Failure error"));
  if (data) {
    res.json({
      timestamp: Date.now(),
      ...data,
    });
    return;
  }
  res.sendStatus(500);
};

const handler = createAsyncHandler(responseHandler);

const router = express.Router();

router.get("/failure", handler((req, res) => {
  return "failure";
}));

router.get("/data", handler(async (req, res) => {
  const res = await testDataFunc();
  res.valid = true;
  return res;
}));

In the above example, the "/failure" route will use the set error handlers and the "/data" route will resolve with {startTime, replyTime, valid, timestamp} as a JSON object.

Alternatively, the legacy behavior described below is available as a default middleware exported as promiseHandler(). You can use promiseHandler(yourfunction) in the express router. Note that res is provided only for header manipulations; no data is expected to be sent by the handling promise.

When the promise resolve, the result is inspected and depending on it three outcome can happen:

  • an object is returned: in that case, the object is used in the reply as-is. It is replied as a JSON.
  • null is returned: an object with a single ok property set to true is replied as a JSON.
  • undefined is returned: the next handle will be called on the request

If the promise reject, the error is left to the error handlers.

Express-validator

The library provides a handful of helpers to take advantage of express-validator. Namely, a dedicated middleware that will run all the validators in an array then checks the result and reply with the appropriate status code.

router.get(
  "/someRoute",
  validate([
    body("someField").isString().isLength({ min: 1 }),
    body("someOtherField").isInt().isLength({ min: 1 }),
  ]),
  (req, res) => {
    // ...
  }
);

In addition, a promise-based validator handler is available:

router.get(
  "/someRoute",
  validatedHandler(
    [
      body("someField").isString().isLength({ min: 1 }),
      body("someOtherField").isInt().isLength({ min: 1 }),
    ],
    async (data: {someField: string, someOtherField: number}): Promise<unknown> => {
      // ...
    },
  ),
);

That function behaves like promiseHandler() but will receive all the validated data as a single argument before req and res.

Authentication middlewares

Some basic authentication-handling middlewares and functions are provided. They are based on JWT used to keep the user's identifier throughout multiple requests.

They are:

  • authMiddleware(): retrieve the token from the request and converts it to a UserType value
  • requireUserMiddleware(): fails if no user is connected or if the user does not pass the provided check
  • setToken(): helper function to generate/set the token used for authentication
  • clearToken(): helper function to unset a cookie (if a cookie is used)
  • getUser(): helper function to get the logged-in user, if applicable

When using a cookie, the process is mostly automatic (as long as the client uses a compliant browser). When using a header, the client-side is responsible for providing the appropriate header with each request and the server is responsible for passing back the token to the client. The header's value is in the form Bearer <token> with the default settings.

Configuration

The auth middlewares and functions all depends on a configuration object implementing the AuthSettings interface.

It's properties are:

  • authName (optional): name for that authentication scheme. Multiple authentication scheme can be used separately.
  • authTokenLocation: either TokenLocation.cookie or TokenLocation.header
  • authTokenName (optional): name of the cookie/header. Defaults to "authtoken" or "Authorization" for cookie or header.
  • authTokenSecret: secret string used to authenticate the authentication token
  • getUserFromIdentifier: function that resolve or return with a user from a string identifier
  • getIdentifierFromUser: function that resolve or return with a string identifier from a user
  • cookieOptions (optional): used only with cookie auth, allow setting some extra cookie options. will enforce httpOnly and secure to true, and defaults to SameSite: strict

The JWT can use ECDSA for signature. To do so, instead of providing a string for authTokenSecret, provide an object:

interface AuthTokenSecretAsymetric {
  privateKey: string;
  publicKey: string;
}

Both should be in PEM format, using the curve256p1 elliptic curve. Such keys can be generated using openssl:

openssl ecparam -name prime256v1 -genkey -noout > key.priv
openssl ec -pubout < key.priv > key.pub

Example

Assuming a server where user's are an object with an "admin" boolean property, the following example shows how to handle authentication in a basic way:

import express from "express";
import {promiseHandler} from "@keeex/utils-express/lib/promise.js";
import * as authMiddleware from "@keeex/utils-express/lib/middleware/auth.js";
import db from "./db/index.js";

const authConfig = {
  authTokenLocation: authMiddleware.TokenLocation.cookie,
  authTokenSecret: "somerandomestring",
  getAuthDataFromIdentifier: identifier => db.models.User.findByPk(parseInt(identifier, 26)),
  getIdentifierFromAuthData: authData => authData.id.toString(26),
  cookie: true,
  header: true,
};

const mwAuthentication = authMiddleware.createAuthMiddleware(authConfig);
const mwRequire = authMiddleware.createRequireMiddleware(authConfig);
const setToken = authMiddleware.createSetToken(authConfig, authMiddleware.TokenLocation.cookie);
const getHeaderToken = authMiddleware.createGetToken(authConfig);
const clearToken = authMiddleware.createClearToken(authConfig);

const router = express.Router();

router.use(mwAuthentication());

router.post(
  "/login",
  promiseHandler(async (req, res) => {
    // Check user credentials
    const user = getUserFromLogin(req.body.login);
    await setToken(user, req, res);
    // Useless, return the user token
    return {
      headerName: "Authorization",
      token: getHeaderToken(user),
    };
  }),
);

router.get(
  "/authenticated",
  mwRequire(),
  promiseHandler((async req, res) => {
    const user = authMiddleware.getUser(req);
    const tokenLocation = authMiddleware.getTokenLocation(req);
    if (tokenLocation) console.log("Token location:", tokenLocation);
    return getSomeData(user);
  }),
);

router.get(
  "/adminonly",
  mwRequire(authdata => authdata.admin),
  promiseHandler((async req, res) => {
    const user = authMiddleware.getUser(req);
    return getSomeData(user);
  }),
);

router.get(
  "/logout",
  (req, res) => {
    clearToken(res);
    res.send({ok: true});
  },
);

For convenience, it is possible to use a single function to retrieve all authentication functions in one call, using default values were applicable (note that the auth middleware, taking no parameters, is not a function in this case):

import express from "express";
import {promiseHandler} from "@keeex/utils-express/lib/promise.js";
import {getAuthFunctions} from "@keeex/utils-express/lib/middleware/auth.js";
import db from "./db/index.js";

const authConfig = {
  authTokenLocation: authMiddleware.TokenLocation.cookie,
  authTokenSecret: "somerandomestring",
  getAuthDataFromIdentifier: identifier => db.models.User.findByPk(parseInt(identifier, 26)),
  getIdentifierFromAuthData: authData => authData.id.toString(26),
  cookie: true,
  header: true,
};

const auth = getAuthFunctions(authConfig);

const router = express.Router();

router.use(auth.mwAuth);

router.post(
  "/login",
  promiseHandler(async (req, res) => {
    // Check user credentials
    const user = getUserFromLogin(req.body.login);
    await auth.setToken(user, req, res);
    // Useless, return the user token
    return {
      headerName: "Authorization",
      token: auth.getHeaderToken(user),
    };
  }),
);

router.get(
  "/authenticated",
  auth.mwRequire(),
  promiseHandler((async req, res) => {
    const user = auth.getAuthDataSafe(req);
    const tokenLocation = auth.getTokenLocationSafe(req);
    console.log("Token location:", tokenLocation);
    return getSomeData(user);
  }),
);

router.get(
  "/adminonly",
  auth.mwRequire(authdata => authdata.admin),
  promiseHandler((async req, res) => {
    const user = auth.getAuthDataSafe(req);
    return getSomeData(user);
  }),
);

router.get(
  "/logout",
  (req, res) => {
    auth.clearToken(res);
    res.send({ok: true});
  },
);

Header configuration

The default configuration for tokens in HTTP header is to use the form Bearer <token base64>. This can be customised by providing an object for the header configuration property. The interface is HeaderSettings.

Authenticated promise-based handlers

Analogous to promiseHandler() and validatedHandler(), the functions promiseAuthHandler() and validatedAuthHandler() are available. They take an additional parameter which is the authFunctions object from the auth middleware, and their handling functions receive the authenticated user as the first argument. They otherwise behave the same.

const auth = getAuthFunctions(/* ... */);

router.get(
  "/someRoute",
  auth.mwRequire(),
  validatedAuthHandler(
    auth,
    [
      body("someField").isString().isLength({ min: 1 }),
      body("someOtherField").isInt().isLength({ min: 1 }),
    ],
    async (user: UserInfo, data: {someField: string, someOtherField: number}): Promise<unknown> => {
      // ...
    },
  ),
);

Basic filter middleware

A low-level IP/token based authorization middleware is available as /lib/middleware/basicfilter.js

Here's a short example of usage:

import basicfilter from "@keeex/utils-express/lib/middleware/basicfilter.js";

router.get(
  "/status",
  basicfilter({
    allowedIP: ["1.2.3.4", "6.5.7.8"],
    allowedToken: "ArthurKingOfTheBriton",
  }),
  (req, res) => res.send({status: "ok"}),
);

The above example will accept all requests from the two given IP (make sure "trust proxy" is set as it should) or for any request with the header Authorization: Bearer ArthurKingOfTheBriton. Both properties can be either array or string.

Swagger-UI middleware

To serve a swagger UI interface based on a pre-built JSON file, you can use the @keeex/utils-express/lib/middleware/apidoc.js middleware.

File cleanup middleware

In case you use multer to receive file you must cleanup the file you receive after processing them. Wrap you multer middleware with this to ensure file is always deleted at the end of the http call.

⚠️ The file is deleted when the res.end function is called; if you handle the file asynchronously after the http call has been resolve the file won't exists anymore.

import fileCleanupWrapper from "@keeex/utils-express/lib/middleware/filecleanup.js";
import multer from "multer";

/**
 * fileCleanupWrapper
 * @param {RequestHandler} requestHandler
 * @param {(error: unkown) => void | Promise<void>} errorHandler
 * @returns RequestHandler
 */

const storage = multer.diskStorage({
  destination: "./",
  filename: (_req, file, cb) => cb(
    null,
    path.basename(tmp.tmpNameSync({
      prefix: `${Date.now()}-upload`,
      postfix: path.extname(file.originalname),
    })),
  ),
});

export const groupLogoUpload = (
  file: string = "file",
): RequestHandler => [
  fileCleanupWrapper(console.error(error)),
  multer({limits: {fileSize: 1_000_000}, storage}).single(file),
];

Token middleware

Simple middleware that extract a string token from an Authorization header and compare it to known values (no deconstruction, structure or anything).

Usage:

import {
  tokenMiddleware,
  getTokenName,
  getTokenValue,
} from "@keeex/utils-express/middleware/token.js";

/** Hardcoded list of tokens */
const knownTokens = {
  serviceA: "token1234",
  serviceB: "token5678",
  serviceC: ["tokenABCD", "tokenEFGH"],
  monitoring: "abcdef",
};

/** Custom functions to match a token with a service name */
const getTokenService = async (token: string): Awaitable<string | undefined> => {
  if (token === "someOtherToken1234") return "someRealService";
}

/** Create the middleware function */
const tokenCheck = tokenMiddleware({
  dynamicTokens: getTokenService,
  header: "Authorization",
  tokens: knownTokens,
  tokenType: "Bearer",
});

/** Will detect any known service, but still proceed if no known token is present. */
route.get(
  "/checkToken",
  tokenCheck(),
  (req, res) => {
    const service = getTokenName(req);
    if (service === false) {
      res.send("No token present");
    } else if (service === null) {
      res.send(`Unknown token present: ${getTokenValue(req)}`);
    } else {
      res.send(`Detected service: ${service}`);
    }
  },
);

/** Will require a known service, any of them */
route.get(
  "/checkToken",
  tokenCheck(true),
  (req, res) => {
    const service = getTokenName(req);
    res.send(`Detected service: ${service}`);
  },
);

/** Will require the "monitoring" service */
route.get(
  "/status",
  tokenCheck("monitoring"),
  (req, res) => {
    res.send("Ok");
  },
);