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

argon2-password

v1.0.0

Published

๐Ÿ” The Bcrypt Successor โ€” Modern password hashing with Argon2id, smart pepper management, and zero-config security. No character limits. No GPU cracking. No compromises.

Readme


Why Argon Fortress?

| Feature | bcryptjs | argon2-password | | --- | --- | --- | | Algorithm | Bcrypt (1999) | Argon2id (2015 PHC Winner) | | Password length | โŒ Limited to 72 chars | โœ… Unlimited | | GPU/ASIC resistance | โš ๏ธ Moderate | โœ… Maximum (memory-hard) | | Secret Pepper | โŒ Manual setup | โœ… Smart auto-loading | | Zero-config | โŒ Requires setup | โœ… Works out of the box | | ESM + CJS | โš ๏ธ Varies | โœ… Dual module support |

Argon2id is the winner of the Password Hashing Competition and is recommended by OWASP for all new applications.


๐Ÿ“ฆ Installation

npm install argon2-password
yarn add argon2-password
pnpm add argon2-password

๐Ÿš€ Quick Start

import { secureHash, secureVerify, isStrong } from 'argon2-password';

// 1. Validate the password
const check = isStrong('MyP@ssw0rd!123');
if (!check.strong) {
  console.log('Weak password:', check.errors);
  process.exit(1);
}

// 2. Hash it (zero-config โ€” works immediately!)
const hash = await secureHash('MyP@ssw0rd!123');
// => "$argon2id$v=19$m=65536,t=4,p=2$..."

// 3. Verify it later
const isValid = await secureVerify('MyP@ssw0rd!123', hash);
// => true

That's it. No configuration files. No environment variables required. It just works.


๐Ÿ”‘ Smart Pepper โ€” Dual-Layer Security

Argon Fortress uses a "Smart Loader" to automatically find and apply a secret pepper to every hash. This adds an extra layer of security on top of the salt that Argon2 already generates.

How the Smart Loader Works

The pepper is resolved in this priority order:

1. ๐Ÿฅ‡ Pepper passed directly in function arguments
2. ๐Ÿฅˆ process.env.AUTH_SECRET environment variable
3. ๐Ÿฅ‰ Machine-derived fallback (development convenience โ€” NOT for production)

โš ๏ธ The fallback pepper is derived from your machine's hostname, OS user, architecture, and platform. It ensures the library never crashes without config, but it is not a substitute for a real secret. Always set AUTH_SECRET in production.

// Priority 1 โ€” Explicit pepper (highest priority)
const hash = await secureHash('password', { pepper: 'my-secret' });

// Priority 2 โ€” Uses process.env.AUTH_SECRET automatically
const hash = await secureHash('password');

// Priority 3 โ€” Uses machine-derived fallback if nothing else is set
// (works, but NOT recommended for production)
const hash = await secureHash('password');

Detecting Fallback Mode

Use isFallbackPepperActive() in your app startup to warn when no real secret is configured:

import { isFallbackPepperActive } from 'argon2-password';

if (isFallbackPepperActive()) {
  console.warn(
    'โš ๏ธ  [argon2-password] No AUTH_SECRET set โ€” using fallback pepper.',
    'Set AUTH_SECRET in your environment for production security.',
  );
}

๐Ÿ›ก๏ธ Setting Up Your Secret Key (Optional but Recommended)

To make your passwords virtually impossible to crack โ€” even if your entire database is leaked โ€” add a private secret key to your server.

Step 1: Create a .env file

Create a file named .env in your project's root folder:

# โš ๏ธ Change this to something unique and random for your app!
AUTH_SECRET=p@ss_W0rd_S3cr3t_99_XYZ_KeepThisPrivate

Step 2: Load it in your app

Use a package like dotenv to load your .env file:

import 'dotenv/config'; // Load .env at the very top
import { secureHash, secureVerify } from 'argon2-password';

// AUTH_SECRET is now automatically used as the pepper!
const hash = await secureHash(userPassword);

Step 3: Add .env to your .gitignore

# NEVER commit your secret key to source control!
.env

Why should I do this?

| Setup | Security Level | What happens if DB is leaked? | | --- | --- | --- | | Without .env | ๐ŸŸ  Moderate | Argon2id is still very hard to brute-force, but the fallback pepper is machine-derived โ€” an attacker on the same machine could reconstruct it. Not recommended for production. | | With .env | ๐ŸŸข Maximum | Passwords are hashed with your private, app-specific key. Even if a hacker steals your database AND your source code, they cannot crack the passwords without this specific .env file from your server. |


๐Ÿ“– API Reference

secureHash(password, options?)

Hash a plaintext password using Argon2id.

| Parameter | Type | Required | Description | | --- | --- | --- | --- | | password | string | โœ… | The plaintext password to hash | | options.pepper | string | โŒ | Custom pepper (overrides env/fallback) | | options.memoryCost | number | โŒ | Memory in KiB, 1024โ€“4194304 (default: 65536 = 64MB) | | options.timeCost | number | โŒ | Iterations, 1โ€“100 (default: 4) | | options.parallelism | number | โŒ | Parallelism, 1โ€“16 (default: 2) | | options.hashLength | number | โŒ | Hash length in bytes, 4โ€“128 (default: 32) |

Throws: ArgonOptionsError if any tuning parameter is outside the allowed range.

Returns: Promise<string> โ€” The encoded Argon2id hash.

const hash = await secureHash('MyP@ssw0rd!123');
const hash2 = await secureHash('MyP@ssw0rd!123', {
  pepper: 'custom-key',
  memoryCost: 131072, // 128 MB
  timeCost: 6,
});

secureVerify(password, hash, options?)

Verify a plaintext password against a stored Argon2id hash.

Tuning parameters (memory, time, parallelism, hashLength) are embedded in the hash itself โ€” only pepper is needed for verification.

| Parameter | Type | Required | Description | | --- | --- | --- | --- | | password | string | โœ… | The plaintext password to verify | | hash | string | โœ… | The stored Argon2id hash string | | options.pepper | string | โŒ | Must match the pepper used during hashing |

Returns: Promise<boolean> โ€” true if valid, false otherwise.

Throws: VerificationError if an operational error occurs (native binding failure, OOM, etc.). A password mismatch or malformed hash returns false without throwing.

import { secureVerify, VerificationError } from 'argon2-password';

try {
  const isValid = await secureVerify('MyP@ssw0rd!123', storedHash);
} catch (err) {
  if (err instanceof VerificationError) {
    console.error('System error during verification:', err.message);
    // err.cause contains the original argon2 error
  }
}

โš ๏ธ Important: You must use the same pepper for verification that was used during hashing. If you change your AUTH_SECRET, old hashes will no longer verify.


isStrong(password)

Validate password strength. Script-agnostic โ€” adapts based on the characters used:

  • Cased scripts (Latin, Cyrillic, Greek): Requires mixed case.
  • Caseless scripts (CJK, Arabic, Thai): Case requirements waived.

| Parameter | Type | Required | Description | | --- | --- | --- | --- | | password | string | โœ… | The password to evaluate |

Returns: { strong: boolean, errors: string[] }

| Rule | Requirement | | --- | --- | | Minimum length | At least 10 characters (by codepoint) | | Letter | At least 1 Unicode letter (\p{L}) | | Mixed case | Required only if cased characters are present | | Digit | At least 1 digit (any script) | | Special character | At least 1 non-letter, non-digit character |

isStrong('MyP@ssw0rd!123');     // { strong: true, errors: [] }
isStrong('ๅฏ†็ ๅพˆๅผบ็š„ๆต‹่ฏ•ๅฎ‰ๅ…จๅฅฝ1!');  // { strong: true, errors: [] }
isStrong('abc123');              // { strong: false, errors: [...] }

๐Ÿ—๏ธ Full Example โ€” Express.js Auth

import 'dotenv/config';
import express from 'express';
import { secureHash, secureVerify, isStrong } from 'argon2-password';

const app = express();
app.use(express.json());

// Sign Up
app.post('/register', async (req, res) => {
  const { email, password } = req.body;

  // Validate password strength
  const strength = isStrong(password);
  if (!strength.strong) {
    return res.status(400).json({ errors: strength.errors });
  }

  // Hash and store
  const hash = await secureHash(password);
  // await db.users.create({ email, passwordHash: hash });

  res.json({ message: 'Account created!' });
});

// Login
app.post('/login', async (req, res) => {
  const { email, password } = req.body;

  // const user = await db.users.findByEmail(email);
  const user = { passwordHash: '...' }; // placeholder

  const isValid = await secureVerify(password, user.passwordHash);
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  res.json({ message: 'Login successful!' });
});

app.listen(3000);

๐Ÿ”ฌ How It Works Under the Hood

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                     User's Password                      โ”‚
โ”‚                    "MyP@ssw0rd!123"                       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              ๐Ÿ” Smart Pepper Loader                      โ”‚
โ”‚                                                          โ”‚
โ”‚   1. Check function args  โ†’  pepper found? Use it.       โ”‚
โ”‚   2. Check AUTH_SECRET    โ†’  env var set?  Use it.        โ”‚
โ”‚   3. Machine-derived fallback โ†’ dev convenience only.     โ”‚
โ”‚                                                          โ”‚
โ”‚   Pepper โ†’ SHA-256 โ†’ 32-byte secret key                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              โš™๏ธ  Argon2id Engine                         โ”‚
โ”‚                                                          โ”‚
โ”‚   โ€ข Memory:      64 MB  (resists GPU attacks)            โ”‚
โ”‚   โ€ข Iterations:  4      (resists brute-force)            โ”‚
โ”‚   โ€ข Parallelism: 2      (uses multi-core)                โ”‚
โ”‚   โ€ข Salt:        auto   (unique per hash)                โ”‚
โ”‚   โ€ข Secret:      pepper (from Smart Loader)              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                   โ”‚
                   โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              ๐Ÿ“ฆ Output                                   โ”‚
โ”‚  "$argon2id$v=19$m=65536,t=4,p=2$<salt>$<hash>"         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โš™๏ธ Module Support

This package ships as both ESM and CommonJS, so it works everywhere:

// ESM (import)
import { secureHash, secureVerify, isStrong } from 'argon2-password';

// CommonJS (require)
const { secureHash, secureVerify, isStrong } = require('argon2-password');

๐Ÿงช Testing

npm test

๐Ÿ“„ License

MIT ยฉ Deepak Kumar