Skip to content

DWTechs/Passken-express.js

Repository files navigation

License: MIT npm version last version release date Jest:coverage

Synopsis

Passken-express.js is an open source password management library for Express.js.
It includes @dwtechs/passken and adds Express middlewares to be used in a node.js service.

  • 🪶 Very lightweight
  • đź§Ş Thoroughly tested
  • đźšš Shipped as EcmaScrypt Express module
  • 📝 Written in Typescript

Support

  • node: 22

This is the oldest targeted versions.

Installation

$ npm i @dwtechs/passken-express

Usage

import * as pk from "@dwtechs/passken-express";
import express from "express";
const router = express.Router();

import user from "../controllers/user.js";
import mail from "../controllers/mail.js";
import consumer from "../controllers/consumer.js";

const passwordOptions = {
  len: 14,
  num: true,
  ucase: false,
  lcase: false,
  sym: false,
  strict: true,
  similarChars: true,
};
pk.init(passwordOptions);

// middleware sub-stacks

// add users
const addMany = [
  user.validate,
  pk.create,
  user.addMany,
  mail.sendRegistration,
];

// Login user
const login = [
  user.validate,
  user.getPwd,
  pk.compare,
  user.isActive,
];


// Routes

// log a user with his email & password
router.post("/", login);

// Add new users
router.post("/", addMany);

Configure

You do not need to initialise the library using pwd.init() if the default config is fine for you.

Passken will start with the following default password configuration :

Options = {
  len: 12,
  num: true,
  ucase: true,
  lcase: true,
  sym: false,
  strict: true,
  similarChars: false,
};

Environment variables

You do not need to intialise the library using pwd.init() if you are using the following environment variables:

  PWD_RAND_LENGTH,
  PWD_RAND_NUMBERS,
  PWD_RAND_UPPERCASE,
  PWD_RAND_LOWERCASE,
  PWD_RAND_SYMBOLS,
  PWD_RAND_STRICT,
  PWD_RAND_SIMILAR_CHARS,
  PWD_SECRET,

These environment variables will update the default values of the lib at start up. So you do not need to init the library in the code.

Note that PWD_SECRET is mandatory.

API Reference

Types

type Options = {
  len: number,
  num: boolean,
  ucase: boolean,
  lcase: boolean,
  sym: boolean,
  strict: boolean,
  similarChars: boolean,
};

PWD Functions

/**
 * Initializes the password generation options for the Passken-express library.
 * 
 * This function sets the global password options that will be used by the `create` function
 * when generating random passwords. The options control password characteristics such as
 * length, character sets, and complexity requirements.
 * 
 * @param {Options} options - Password generation options from @dwtechs/passken
 * @param {number}  options.len - Password length (minimum characters)
 * @param {boolean} options.num - Include numbers in password
 * @param {boolean} options.ucase - Include uppercase letters
 * @param {boolean} options.lcase - Include lowercase letters  
 * @param {boolean} options.sym - Include symbols in password
 * @param {boolean} options.strict - Password must include at least one character from each enabled pool
 * @param {boolean} options.similarChars - Allow visually similar characters (l, I, 1, o, O, 0)
 * 
 * @returns {void}
 * 
 * **Input Properties:**
 * - `options` (Options object) - Password generation configuration
 * 
 * **Output Properties:**
 * - None (sets global configuration)
 * 
 * @example
 * ```typescript
 * import { init } from '@dwtechs/passken-express';
 * 
 * // Initialize with custom password options
 * init({
 *   len: 16,
 *   num: true,
 *   ucase: true,
 *   lcase: true,
 *   sym: true,
 *   strict: true,
 *   similarChars: false
 * });
 * ```
 */
function init(options: Options): void {}

/**
 * Express middleware to compare a user-provided password with a stored hashed password.
 * 
 * This middleware validates that a plaintext password from the request matches a hashed
 * password from the database. It extracts the password from the request body and the
 * hash from either the response rows or response object, then uses Passken's secure
 * comparison function to verify the match.
 * 
 * @param {Request} req - Express request object containing the password
 * @param {MyResponse} res - Express response object containing the database hash
 * @param {NextFunction} next - Express next function to continue middleware chain
 * 
 * @returns {void} Calls next() to continue, or next(error) on failure
 * 
 * @throws {InvalidPasswordError} If the password is invalid or does not match the hash (HTTP 400)
 * @throws {InvalidBase64SecretError} If the secret is not a valid base64 string (HTTP 400)
 * @throws {Object} Will call next() with error object containing:
 *   - statusCode: 400 - When password is missing from request body
 *   - statusCode: 400 - When hash is missing from response data
 *   - statusCode: 401 - When password doesn't match the stored hash
 * 
 * @example
 * ```typescript
 * import { compare } from '@dwtechs/passken-express';
 * 
 * // Usage in Express route after database query
 * app.post('/login', getUserFromDB, compare, (req, res) => {
 *   res.json({ message: 'Login successful' });
 * });
 * 
 * // Request body should contain:
 * // { "password": "user-password" } or { "pwd": "user-password" }
 * 
 * // Response should contain hash from database:
 * // res.rows[0].password or res.rows[0].pwd or res.password or res.pwd
 * ```
 */
function compare(req: Request, res: MyResponse, next: NextFunction): void {}

/**
 * Express middleware to generate random passwords and encrypt them for multiple users.
 * 
 * This middleware generates secure random passwords for multiple user records and encrypts
 * them using Passken's encryption function. It processes an array of user objects in the
 * request body, adding both plaintext and encrypted password fields to each record.
 * The plaintext passwords can be sent to users (e.g., via email) while encrypted passwords
 * are stored in the database.
 * 
 * @param {Request} req - Express request object containing user records in body.rows
 * @param {Response} _res - Express response object (not used in this function)
 * @param {NextFunction} next - Express next function to continue middleware chain
 * 
 * @returns {void} Calls next() to continue, or next(error) on failure
 * 
 * @throws {InvalidPasswordError} If password generation or encryption fails (HTTP 400)
 * @throws {InvalidBase64SecretError} If the secret is not a valid base64 string (HTTP 400)
 * @throws {Object} Will call next() with error object containing:
 *   - statusCode: 400 - When req.body.rows is missing or not an array
 * 
 * @example
 * ```typescript
 * import { create } from '@dwtechs/passken-express';
 * 
 * // Usage in Express route for bulk user creation
 * app.post('/users/bulk', create, saveUsersToDatabase, (req, res) => {
 *   // Send plaintext passwords to users via email
 *   req.body.rows.forEach(user => {
 *     sendPasswordEmail(user.email, user.pwd);
 *   });
 *   res.json({ message: 'Users created successfully' });
 * });
 * 
 * // Request body should contain:
 * // { "rows": [{ "name": "User1", "email": "user1@example.com" }, ...] }
 * 
 * // After processing, each row will have:
 * // { "name": "User1", "email": "user1@example.com", "pwd": "generated-password", "encryptedPwd": "encrypted-hash" }
 * ```
 */
function create(req: Request, res: Response, next: NextFunction): void {}

Password Comparison

The function will look for a password value from the client request body :

const pwd = req.body?.password || req.body?.pwd || req.body?.pwdHash.

It will then look for the hashed password stored in the database :

const hash = res.password 
  || res.pwd 
  || res.pwdHash
  || res.rows[0].password 
  || res.rows[0].pwd 
  || res.rows[0].pwdHash
  || res.locals.rows[0].password 
  || res.locals.rows[0].pwd 
  || res.locals.rows[0].pwdHash;

Password generation

The function will loop through an array in req.body.rows.

It will throw an error if req.body.rows is missing or empty.

New passwords will be added into req.body.rows[i].pwd. Encrypted passwords will be added into req.body.rows[i].encryptedPwd .

PWD Options

Any of these can be passed into the options object for each function.

Name type Description Default
len Integer Minimal length of password. 12
num* Boolean use numbers in password. true
sym* Boolean use symbols in password true
lcase* Boolean use lowercase in password true
ucase* Boolean use uppercase letters in password. true
strict Boolean password must include at least one character from each pool. true
similarChars Boolean allow close looking chars. false

*At least one of those options must be true.

Symbols used : !@#%*_-+=:;?><,./() Similar characters : l, I, 1, o, O, 0

Logs

Passken-express.js uses @dwtechs/Winstan library for logging. All logs are in debug mode. Meaning they should not appear in production mode.

Contributors

Passken-express.js is still in development and we would be glad to get all the help you can provide. To contribute please read contributor.md for detailed installation guide.

Stack

Purpose Choice Motivation
repository Github hosting for software development version control using Git
package manager npm default node.js package manager
language TypeScript static type checking along with the latest ECMAScript features
module bundler Rollup advanced module bundler for ES6 modules
unit testing Jest delightful testing with a focus on simplicity

About

Safe pass encryption and other useful tools for Express.js

Resources

License

Stars

Watchers

Forks

Packages

No packages published