Passken.js is an open source password and JWT management library for Node.js to create, encrypt and compare safely.
- Only 1 dependency to check inputs variables
- Very lightweight
- Thoroughly tested
- EcmaScrypt module
- Works in Javascript and Typescript
- Written in Typescript
- Node.js: 22
This is the oldest targeted versions.
The library uses node:crypto.
$ npm i @dwtechs/passken
Example of use with Express.js using ES6 module format
import { compare, randomPwd, encrypt, sign, verify } from "@dwtechs/passken";
const { PWD_SECRET, TOKEN_SECRET } = process.env;
/**
* This function checks if a user-provided password matches a stored hashed password in a database.
* It takes a request object req and a response object res as input, and uses a pass service to compare the password.
* If the password is correct, it calls the next() function to proceed with the request.
* If the password is incorrect or missing, it calls next() with an error status and message.
*/
function comparePwd(req, res, next) {
const pwd = req.body.pwd; // from request
const hash = req.user.hash; //from db
if (compare(pwd, hash, PWD_SECRET))
return next();
return next({ status: 401, msg: "Wrong password" });
}
/**
* Generates a random password for a user and encrypts it.
*/
function createPwd(req, res, next) {
const user = req.body.user;
const options = {
len: 14,
num: true,
ucase: true,
lcase: true,
sym: true,
strict: true,
similarChars: true,
};
user.pwd = randomPwd(options);
user.pwdHash = encrypt(user.pwd, PWD_SECRET);
next();
}
// JWT
function signToken(req, res, next) {
res.jwt = sign(req.userId, 3600, "access", [TOKEN_SECRET]);
next();
}
function verifyToken(req, res, next) {
res.decodedToken = verify(req.token, [TOKEN_SECRET]);
next();
}
export {
comparePwd,
createPwd,
signToken,
verifyToken,
};
Passken will start with the following default password configuration :
Options = {
len: 12,
num: true,
ucase: true,
lcase: true,
sym: false,
strict: true,
similarChars: false,
};
You can update password default configuration using the following environment variables :
PWD_LENGTH,
PWD_NUMBERS,
PWD_UPPERCASE,
PWD_LOWERCASE,
PWD_SYMBOLS,
PWD_STRICT,
PWD_SIMILAR_CHARS,
These environment variables will update the default values of the lib at start up. With this strategy you do not need to send options parameter in the randomPwd() method anymore.
// Password
type Options = {
len: number,
num: boolean,
ucase: boolean,
lcase: boolean,
sym: boolean,
strict: boolean,
similarChars: boolean,
};
// JWT
type Type = "access" | "refresh";
type Header = {
alg: string,
typ: string,
kid: number,
};
type Payload = {
iss: number | string,
iat: number,
nbf: number,
exp: number,
typ: Type,
}
// Default values
let saltRnds = 12
let digest = "sha256";
let keyLen = 64;
/**
* Returns the number of salt rounds used for hashing.
*
* @returns {number} The number of salt rounds.
*/
function getSaltRounds(): number {}
/**
* Sets the number of salt rounds for hashing.
*
* @param {number} rnds - The number of salt rounds to set. Must be a valid integer between 12 and 100.
* @returns {boolean} True if the salt rounds were successfully set, otherwise false.
*/
function setSaltRounds(rnds: number): boolean {} // between 12 and 100
/**
* Returns the key length used for hashing.
*
* @returns {number} The key length.
*/
function getKeyLen(): number {}
/**
* Sets the key length to the specified value for hashing.
*
* @param {number} len - The desired key length. Must be a valid integer between 2 and 256.
* @returns {boolean} True if the key length was successfully set; otherwise false.
*/
function setKeyLen(r: number): boolean {} // between 2 and 256
/**
* Returns the hash function used for hashing.
*
* @returns {string} The hash function.
*/
function getDigest(): string {}
/**
* Sets the hash function used for hashing.
* the list of available digests is returned by getDigests()
*
* @param {string} func - The hash function. Must be a valid value from the list of available hash functions.
* @returns {boolean} True if the hash function was successfully set; otherwise false.
*/
function setDigest(d: string): boolean {}
/**
* Returns the list of available hash functions.
*
* @returns {string[]} The list of available hash functions.
*/
function getDigests(): string[] {}
/**
* Encrypts a password using a base64 encoded secret.
*
* @param {string} pwd - The password to encrypt. Must be a non-empty string.
* @param {string} b64Secret - The base64 encoded secret used for encryption. Must be a valid base64 encoded string.
* @returns {string} The encrypted password as a hex string prefixed with a random salt.
* @throws {Error} If pwd is not a non-empty string or b64Secret is not a valid base64 encoded string.
*/
function encrypt( pwd: string,
b64Secret: string
): string | false {}
/**
* Compares a plaintext password with a hashed password using a secret.
*
* @param {string} pwd - The plaintext password to compare.
* @param {string} hash - The hashed password to compare against.
* @param {string} b64Secret - The base64 encoded secret used for hashing.
* @returns {boolean} true if the password matches the hash, false otherwise.
*/
function compare( pwd: string,
hash: string,
b64Secret: string
): boolean {}
/**
* Generate a random password.
*
* @param {Partial<Options>} opts - The options to generate the password.
* @returns {string} The generated password.
*
*/
function randomPwd(opts: Partial<Options> = defOpts): string {}
// Default values
const header {
alg: "HS256", // HMAC using SHA-256 hash algorithm
typ: "JWT", // JSON Web Token
kid: 0, // Random key ID
};
/**
* Signs a JWT (JSON Web Token) with the given parameters.
*
* @param {number|string} iss - The issuer of the token, which can be a string or a number.
* @param {number} duration - The duration for which the token is valid, in seconds.
* @param {Type} type - The type of the token, either "access" or "refresh".
* @param {string[]} b64Keys - An array of base64 encoded secrets used for signing the token.
* @returns {string} The signed JWT as a string.
* @throws Will throw an error if `iss` is not a string or a number.
* @throws Will throw an error if `b64Secrets` is not an array.
* @throws Will throw an error if `duration` is not a positive number.
* @throws Will throw an error if the secret cannot be decoded.
*/
function sign( iss: number | string,
duration: number,
type: Type,
b64Keys: string[]
): string;
/**
* Verifies a JWT token using the provided base64-encoded secrets.
*
* @param {string} token - The JWT token to verify.
* @param {string[]} b64Keys - An array of base64-encoded secrets used for verification.
* @param {boolean} ignoreExpiration - Optional flag to ignore the expiration time of the token. Defaults to false.
* @returns {Payload} The decoded payload of the JWT token as a string.
* @throws Will throw an error if the token does not have 3 segments.
* @throws Will throw an error if the token does not have a header, payload, and signature.
* @throws Will throw an error if `b64Keys` is not an array.
* @throws Will throw an error if the header or payload are not valid JSON.
* @throws Will throw an error if the algorithm or token type are not supported.
* @throws Will throw an error if the "kid" in the header is invalid.
* @throws Will throw an error if the token cannot be used yet (nbf claim).
* @throws Will throw an error if the token has expired (exp claim).
* @throws Will throw an error if the secret is not valid base64 url-sale encoded.
* @throws Will throw an error if the signature is invalid.
*/
function verify( token: string,
b64Keys: string[],
ignoreExpiration = false
): Payload;
/**
* Generates a random string of the specified length, encoded in base64.
*
* @param {number} [length=32] - The length of the random string to generate. Defaults to 32 if not specified.
* @returns {string} The generated random string encoded in base64.
*/
randomSecret(length = 32): string
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
You can use Passken directly as Express.js middlewares using @dwtechs/passken-express library. This way you do not have to write express controllers yourself to use Passken.
Passken.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.
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.js | advanced module bundler for ES6 modules |
unit testing | Jest | delightful testing with a focus on simplicity |