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

@bernierllc/crypto-utils

v1.0.6

Published

Comprehensive cryptographic utilities including key generation, JWT tokens, magic links, and secure hashing for BernierLLC ecosystem

Readme

@bernierllc/crypto-utils

Comprehensive cryptographic utilities including key generation, JWT tokens, magic links, and secure hashing for modern applications.

Installation

npm install @bernierllc/crypto-utils

Quick Start

import { 
  generateApiKey, 
  generateAccessToken, 
  generateEmailMagicLink,
  verifyJWT,
  constantTimeCompare 
} from '@bernierllc/crypto-utils';

// Generate an API key with sensible defaults
const apiKey = await generateApiKey();
console.log(apiKey); // ak_a1b2c3d4e5f6...

// Generate JWT access token
const accessToken = generateAccessToken({ 
  sub: 'user123', 
  email: '[email protected]' 
}, 'your-secret');

// Generate magic link for email authentication
const magicLink = generateEmailMagicLink('user123', '[email protected]', 'your-secret');

// Secure password verification
const isValid = constantTimeCompare(providedPassword, storedPasswordHash);

Core Features

🔐 Key Generation

  • Multiple Algorithms: Random bytes, UUID v4, custom patterns
  • Multiple Encodings: Hex, Base64, Base58 (Bitcoin-style)
  • Security Features: Entropy validation, collision detection, safe hashing

🎟️ JWT Tokens

  • Standards Compliant: RFC 7519 JWT implementation
  • Multiple Algorithms: HS256, HS384, HS512
  • Claims Validation: Expiration, issuer, audience, subject

✉️ Magic Links

  • Email Authentication: Secure passwordless login
  • Password Reset: Time-limited reset tokens
  • URL-Safe: Base64URL encoding for web compatibility
  • TOTP Support: Time-based one-time passwords

🛡️ Security Utilities

  • Constant-Time Comparison: Prevent timing attacks
  • Password Verification: Secure hash validation
  • Token Validation: Comprehensive security checks

API Reference

Key Generation

Core Generation Functions

generateRandomKey(options?)

Generate cryptographically secure random keys using crypto.randomBytes.

import { generateRandomKey } from '@bernierllc/crypto-utils';

const result = await generateRandomKey({
  length: 32,           // Key length in bytes
  prefix: 'ak_',        // Optional prefix
  encoding: 'hex',      // 'hex' | 'base64' | 'base58'
  validateEntropy: true, // Validate entropy requirements
  minEntropyBits: 128,  // Minimum entropy in bits
  checkUnique: async (key) => !await db.keyExists(key), // Collision check
  maxRetries: 5         // Max collision retry attempts
});

console.log(result.key);      // Generated key string
console.log(result.entropy);  // Estimated entropy in bits
console.log(result.metadata); // Generation metadata

Convenience Functions

Pre-configured key generators with sensible defaults:

import { 
  generateApiKey,       // ak_ + 32 bytes + hex
  generateSecretKey,    // sk_ + 48 bytes + base64  
  generateSessionToken, // sess_ + UUID + base58
  generateLicenseKey    // lic_ + pattern XXXX-XXXX-XXXX-XXXX
} from '@bernierllc/crypto-utils';

const apiKey = await generateApiKey();          // ak_a1b2c3...
const secret = await generateSecretKey();       // sk_SGVsbG8...
const session = await generateSessionToken();   // sess_23456789...
const license = await generateLicenseKey();     // lic_A1B2-C3D4...

JWT Tokens

Token Generation

generateJWT(payload, secret, options?)

Generate signed JWT tokens with custom claims.

import { generateJWT } from '@bernierllc/crypto-utils';

const token = generateJWT({
  sub: 'user123',
  email: '[email protected]',
  role: 'admin'
}, 'your-jwt-secret', {
  algorithm: 'HS256',     // HS256 | HS384 | HS512
  expiresIn: 3600,        // 1 hour in seconds
  issuer: 'your-app',
  audience: 'api',
  includeIssuedAt: true   // Include iat claim
});

verifyJWT(token, secret, options?)

Verify and validate JWT tokens.

import { verifyJWT } from '@bernierllc/crypto-utils';

const result = verifyJWT(token, 'your-jwt-secret', {
  issuer: 'your-app',      // Expected issuer
  audience: 'api',         // Expected audience
  clockTolerance: 30,      // Allow 30 seconds clock skew
  ignoreExpiration: false  // Enforce expiration
});

if (result.valid) {
  console.log('User:', result.payload?.sub);
  console.log('Expires in:', result.expiresIn, 'seconds');
} else {
  console.error('Invalid token:', result.error);
}

Convenience Token Functions

import { 
  generateAccessToken,  // 1 hour expiry, HS256
  generateRefreshToken, // 7 days expiry, HS256
} from '@bernierllc/crypto-utils';

// Generate access token (1 hour expiry)
const accessToken = generateAccessToken({
  sub: 'user123',
  email: '[email protected]'
}, 'your-secret');

// Generate refresh token (7 days expiry)
const refreshToken = generateRefreshToken({
  sub: 'user123'
}, 'your-secret');

Magic Links

Email Authentication Links

generateMagicLink(userId, email, secret, options?)

Generate secure magic links for passwordless authentication.

import { generateMagicLink } from '@bernierllc/crypto-utils';

const result = generateMagicLink('user123', '[email protected]', 'your-secret', {
  expirationMinutes: 15,  // Link expires in 15 minutes
  action: 'login',        // Action type
  customData: {           // Additional data
    ip: '192.168.1.1',
    userAgent: 'Mozilla/5.0...'
  }
});

const magicUrl = `https://yourapp.com/auth/verify?token=${result.token}`;
console.log('Magic link expires at:', new Date(result.expiresAt));

verifyMagicLink(token, secret, options?)

Verify magic link tokens.

import { verifyMagicLink } from '@bernierllc/crypto-utils';

const result = verifyMagicLink(token, 'your-secret');

if (result.valid) {
  console.log('User ID:', result.payload?.userId);
  console.log('Email:', result.payload?.email);
  console.log('Action:', result.payload?.action);
  console.log('Remaining time:', result.remainingMinutes, 'minutes');
  
  // Authenticate user
  await authenticateUser(result.payload.userId);
} else {
  console.error('Invalid magic link:', result.error);
}

Convenience Magic Link Functions

import { 
  generateEmailMagicLink,    // 15 min expiry, email_auth action
  generatePasswordResetLink  // 30 min expiry, password_reset action
} from '@bernierllc/crypto-utils';

// Email verification link
const emailLink = generateEmailMagicLink('user123', '[email protected]', 'secret');

// Password reset link  
const resetLink = generatePasswordResetLink('user123', '[email protected]', 'secret');

One-Time Passwords (OTP)

import { generateOTP, generateTOTP, verifyTOTP } from '@bernierllc/crypto-utils';

// Simple numeric OTP
const otp = generateOTP(6); // 123456

// Time-based OTP (Google Authenticator compatible)
const secret = '48656c6c6f21deadbeef'; // Hex-encoded secret
const totp = generateTOTP(secret, {
  timeStep: 30,    // 30-second windows
  digits: 6,       // 6-digit codes
  algorithm: 'sha1' // sha1 | sha256 | sha512
});

// Verify TOTP code
const isValid = verifyTOTP(userProvidedCode, secret, {
  window: 1 // Allow ±1 time window (90 seconds total)
});

Security Utilities

Constant-Time Comparison

Prevent timing attacks when comparing sensitive values.

import { 
  constantTimeCompare,
  constantTimeCompareHex,
  validateSecureToken
} from '@bernierllc/crypto-utils';

// Basic constant-time string comparison
const isMatch = constantTimeCompare(providedToken, expectedToken);

// Hex comparison (case-insensitive)  
const hexMatch = constantTimeCompareHex('deadbeef', 'DEADBEEF'); // true

// Secure token validation with options
const isValid = validateSecureToken(providedToken, expectedToken, {
  caseSensitive: false,  // Case-insensitive comparison
  trimWhitespace: true,  // Trim whitespace
  maxLength: 1000        // Maximum token length
});

Password Hash Verification

import { verifyPasswordHash } from '@bernierllc/crypto-utils';

// Custom hash function (use bcrypt, scrypt, etc. in production)
const hashPassword = (password: string) => {
  return crypto.createHash('sha256').update(password + 'salt').digest('hex');
};

const isValidPassword = verifyPasswordHash(
  providedPassword,
  storedPasswordHash,
  hashPassword
);

Timing-Safe Array Operations

import { timingSafeIncludes } from '@bernierllc/crypto-utils';

const allowedTokens = ['token1', 'token2', 'token3'];
const isAllowed = timingSafeIncludes(allowedTokens, userToken);

Complete Authentication Flow Example

import {
  generateEmailMagicLink,
  verifyMagicLink,
  generateAccessToken,
  generateRefreshToken,
  verifyJWT
} from '@bernierllc/crypto-utils';

const JWT_SECRET = process.env.JWT_SECRET!;
const MAGIC_SECRET = process.env.MAGIC_SECRET!;

// Step 1: Send magic link via email
async function sendMagicLink(email: string) {
  const user = await getUserByEmail(email);
  if (!user) throw new Error('User not found');
  
  const magicLink = generateEmailMagicLink(user.id, email, MAGIC_SECRET, {
    expirationMinutes: 10
  });
  
  const url = `https://app.com/auth/verify?token=${magicLink.token}`;
  await sendEmail(email, 'Login to Your Account', `Click: ${url}`);
}

// Step 2: Verify magic link and issue tokens
async function verifyMagicLinkAndIssueTokens(token: string) {
  const verification = verifyMagicLink(token, MAGIC_SECRET);
  
  if (!verification.valid) {
    throw new Error(`Invalid magic link: ${verification.error}`);
  }
  
  const userId = verification.payload!.userId;
  const user = await getUserById(userId);
  
  const accessToken = generateAccessToken({
    sub: userId,
    email: user.email,
    role: user.role
  }, JWT_SECRET);
  
  const refreshToken = generateRefreshToken({
    sub: userId
  }, JWT_SECRET);
  
  return { accessToken, refreshToken, user };
}

// Step 3: Validate API requests
async function authenticateRequest(authHeader: string) {
  const token = authHeader.replace('Bearer ', '');
  const verification = verifyJWT(token, JWT_SECRET);
  
  if (!verification.valid) {
    throw new Error(`Authentication failed: ${verification.error}`);
  }
  
  return verification.payload;
}

Security Best Practices

Key Generation

  • Minimum 128 bits of entropy for production keys
  • Use generateRandomKey() for maximum entropy
  • Implement collision checking with checkUnique

JWT Security

  • Use strong secrets (256+ bits of entropy)
  • Short expiration times for access tokens (15-60 minutes)
  • Validate all claims (exp, iss, aud, etc.)
  • Use HTTPS only for token transmission

Magic Link Security

  • Short expiration times (5-15 minutes for login, 30 minutes for password reset)
  • Single use only - invalidate after verification
  • Rate limiting - prevent magic link spam
  • HTTPS required - never send over HTTP

Constant-Time Operations

  • Always use for passwords and sensitive tokens
  • Use for session validation and API key checking
  • Avoid string length leaks in error messages

General Security

  • Never log secrets or tokens in production
  • Use environment variables for secrets
  • Implement proper key rotation policies
  • Use HTTPS everywhere for token transmission

Error Handling

import { generateJWT, verifyJWT, generateMagicLink } from '@bernierllc/crypto-utils';

try {
  // Token generation
  const token = generateJWT(payload, secret);
  
  // Token verification
  const result = verifyJWT(token, secret);
  if (!result.valid) {
    // Handle specific errors
    if (result.error?.includes('expired')) {
      console.log('Token expired, refresh required');
    } else if (result.error?.includes('signature')) {
      console.log('Invalid token signature');
    }
  }
  
  // Magic link generation
  const magicLink = generateMagicLink(userId, email, secret, {
    expirationMinutes: 5
  });
  
} catch (error) {
  console.error('Crypto operation failed:', error.message);
}

TypeScript Support

Full TypeScript support with comprehensive type definitions:

import type { 
  // Key generation types
  KeyOptions, 
  GenerationResult, 
  ValidationResult,
  KeyEncoding,
  KeyAlgorithm,
  
  // JWT types
  JWTPayload,
  JWTOptions,
  JWTVerifyResult,
  
  // Magic link types
  MagicLinkOptions,
  MagicLinkResult,
  MagicLinkVerifyResult
} from '@bernierllc/crypto-utils';

// Strongly typed JWT payload
const payload: JWTPayload = {
  sub: 'user123',
  email: '[email protected]',
  exp: Math.floor(Date.now() / 1000) + 3600
};

// Strongly typed options
const keyOptions: KeyOptions = {
  length: 32,
  encoding: 'hex',
  validateEntropy: true
};

Performance

  • High throughput: >10,000 operations/second
  • Efficient encoding: Optimized implementations
  • Minimal dependencies: Zero runtime dependencies
  • Memory efficient: Streaming operations where possible

Migration from @bernierllc/api-key-generator

The package maintains full backward compatibility:

// All existing imports continue to work
import { 
  generateApiKey,
  generateSecretKey,
  generateRandomKey,
  validateKeyFormat
} from '@bernierllc/crypto-utils'; // was @bernierllc/api-key-generator

License

MIT License - Copyright (c) 2025 Bernier LLC

See Also