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 🙏

© 2025 – Pkg Stats / Ryan Hefner

auth-verify

v1.12.1

Published

A simple Node.js library for sending and verifying OTP via email, SMS and Telegram bot. And generating TOTP codes and QR codes. And handling JWT with Cookies. And also handling passwordless logins with passkeys/webauth. And handling magiclink passwordless

Readme

auth-verify

AuthVerify is a modular authentication library for Node.js, providing JWT, OTP, TOTP, Passkeys (WebAuthn), Magic Links, Sessions, and OAuth helpers. You can easily register custom senders for OTPs or notifications. Auth-verify now supports REST API for generating, sending OTP with email/SMS and verifying it.


🧩 Installation

# from npm (when published)
npm install auth-verify

# or locally during development
# copy the package into your project and `require` it`

⚙️ Quick overview

  • AuthVerify (entry): constructs and exposes .jwt, .otp, (optionally) .session, .totp and .oauth managers.
  • JWTManager: sign, verify, decode, revoke tokens. Supports storeTokens: "memory" | "redis" | "none" and middleware with custom cookie, header, and token extraction.
  • OTPManager: generate, store, send, verify, resend OTPs. Supports storeTokens: "memory" | "redis" | "none". Supports email, SMS helper, Telegram bot, and custom dev senders.
  • TOTPManager: generate, verify uri, codes and QR codes.
  • SessionManager: simple session creation/verification/destroy with memory or Redis backend.
  • OAuthManager: Handle OAuth 2.0 logins for 20+ providers.
  • PasskeyManager: Handle passwordless login and registration using WebAuthn/passkey.
  • MagicLinkManager: Handle passwordless login with magic link generation and verification.
  • CrpytoManager: Handle hashing passwords or another data with algorithms like: "pbkdf2" and "scrypt"

🚀 Example: Initialize library (CommonJS)

const AuthVerify = require('auth-verify');

const auth = new AuthVerify({
  jwtSecret: 'your_jwt_secret',
  cookieName: 'jwt_token',
  otpExpiry: 300,        // in seconds
  storeTokens: 'memory', // or 'redis'
  redisUrl: 'redis://localhost:6379',
  totp: { digits: 6, step: 30, alg: 'SHA1' },
  rpName: 'myApp',
  passExp: '2m',
  mlSecret: 'ml_secret',
  mlExpiry: '5m',
  appUrl: 'https://yourapp.com'
});

Options explained:

| Option | Default | Description | | ------------- | -------------------------------------- | ---------------------------------------- | | jwtSecret | "jwt_secret" | Secret key for JWT signing | | cookieName | "jwt_token" | Cookie name for JWT storage | | otpExpiry | 300 | OTP expiration in seconds | | storeTokens | "memory" | Token storage type (memory or redis) | | redisUrl | undefined | Redis connection string if using Redis | | totp | { digits: 6, step: 30, alg: 'SHA1' } | TOTP configuration | | rpName | "auth-verify" | Relying party name for Passkeys | | passExp | "2m" | Passkey expiration duration | | mlSecret | "ml_secret" | Magic link secret | | mlExpiry | "5m" | Magic link expiration duration | | appUrl | "https://yourapp.com" | App base URL for Magic Links |


🔐 JWT Usage

🔐 AuthVerify JWT API Guide

AuthVerify includes a powerful jwt manager that simplifies JSON Web Token (JWT) authentication. It supports automatic cookie handling, memory or Redis token storage, and an Express middleware for route protection.

⚙️ Setup

const AuthVerify = require('auth-verify');

const auth = new AuthVerify({
  jwtSecret: 'super_secret_key',
  cookieName: 'auth_token',
  storeTokens: 'redis',         // or 'memory'
  redisUrl: 'redis://localhost:6379',
  useAlg: 'HS256',              // or any supported algorithm
});

After initialization, the JWT system is accessible via auth.jwt.

🧩 JWT Methods Overview

| Method | Description | | ------------------------------------------- | ------------------------------------------------------------ | | auth.jwt.sign(payload, expiry?, options?) | Creates a JWT token and optionally sets it in a cookie | | auth.jwt.verify(tokenOrReq) | Verifies a token or extracts it automatically from a request | | auth.jwt.decode(token) | Decodes JWT payload without verification | | auth.jwt.revoke(token, revokeTime?) | Revokes a token immediately or after a timeout | | auth.jwt.isRevoked(token) | Checks whether a token has been revoked | | auth.jwt.protect(options?) | Express middleware to protect API routes | | auth.jwt.readCookie(req, name) | Reads a JWT from cookies manually | | auth.jwt.issue(user) | Issues an access token and a refresh token | | auth.jwt.refresh(refreshToken) | Refreshes an access token using a valid refresh token |

🪄 auth.jwt.sign(payload, expiry?, options?)

Signs a new JWT token. Can automatically store it in memory/Redis and set an HTTP-only cookie for browser clients.

const token = await auth.jwt.sign(
  { id: 'user_123', role: 'admin' },
  '2h', // expiry time
  { res } // Express res object to auto-set cookie
);

Parameters:

| Name | Type | Default | Description | | ---------------- | ------------------ | ------- | -------------------------------------------------------- | | payload | object | — | Data to include in the JWT | | expiry | string \| number | '1h' | Expiration time (5m, 2h, 1d, etc.) | | options.res | Response | — | Express response object (sets cookie automatically) | | options.secure | boolean | true | If false, cookie is not secure (for localhost testing) |

Returns:

Promise<string> → The generated JWT token.

auth.jwt.verify(input)

Verifies and decodes a token. You can pass either a raw JWT token string or an Express request object. When passing req, the library automatically extracts the token from:

  • Authorization header (Bearer <token>)
  • Cookies (auth_token by default)
// 1️⃣ Verify a token string
const decoded = await auth.jwt.verify(token);

// 2️⃣ Verify directly from a request
const decoded = await auth.jwt.verify(req);

Returns:

Promise<object> → Decoded payload if valid, throws error if invalid or revoked.

🧠 auth.jwt.decode(token)

Decodes a token without verifying the signature (useful for inspection or debugging).

const data = await auth.jwt.decode(token);

Returns: Decoded object or null.

🧩 auth.jwt.issue(user)

Issues a new access token and a refresh token for a user.

const { accessToken, refreshToken } = auth.jwt.issue({ id: 'user_123' });
  • Access token: short-lived, used for authentication.
  • Refresh token: long-lived, used to get a new access token without logging in again.

Parameters: | Name | Type | Description | | ---- | ------ | ------------------------------ | | user | object | User object with id property | Returns:

{ accessToken: string, refreshToken: string }

🔄 auth.jwt.refresh(refreshToken)

Refreshes an access token using a valid refresh token.

const newTokens = auth.jwt.refresh(refreshToken);
  • Validates the refresh token.
  • Issues a new access token and refresh token pair.
  • Throws an error if the token is invalid or expired.

Parameters: | Name | Type | Description | | ------------ | ------ | ---------------------------- | | refreshToken | string | A valid refresh token string | Returns:

{ accessToken: string, refreshToken: string }

auth.jwt.revoke(token, revokeTime?)

Revokes a token immediately or after a specified duration.

await auth.jwt.revoke(token);      // revoke now
await auth.jwt.revoke(token, '5m'); // revoke after 5 minutes

If using:

  • memory: the token is removed from internal store.
  • redis: the key is deleted or set to expire.

🚫 auth.jwt.isRevoked(token)

Checks if a token is revoked (missing in memory or Redis).

const revoked = await auth.jwt.isRevoked(token);
if (revoked) console.log('Token is no longer valid.');

Returns: boolean

🛡️ auth.jwt.protect(options)

Express middleware for protecting routes that require authentication.

app.get('/dashboard', auth.jwt.protect(), (req, res) => {
  res.json({ user: req.user });
});

Or with extra security options:

app.get('/admin',
  auth.jwt.protect({
    requiredRole: 'admin',
    attachProperty: 'sessionUser',
    onError: (err, req, res) => res.status(403).json({ error: err.message })
  }),
  (req, res) => {
    res.json({ message: `Welcome ${req.sessionUser.id}` });
  });

Options:

| Name | Type | Default | Description | | ---------------- | ---------- | ------------------------- | --------------------------------------------- | | attachProperty | string | 'user' | Where decoded data is attached on the request | | requiredRole | string | null | Restricts route access by user role | | cookieName | string | Inherited from AuthVerify | Cookie name to extract token | | headerName | string | 'authorization' | Header name to look for JWT | | extractor | function | — | Custom token extraction logic | | onError | function | — | Custom error handler (err, req, res) |

🍪 auth.jwt.readCookie(req, name)

Manually extract a JWT from a cookie:

const token = auth.jwt.readCookie(req, 'auth_token');

Returns: string | null

🧩 Full Example

const express = require('express');
const AuthVerify = require('auth-verify');

const auth = new AuthVerify({
  jwtSecret: 'supersecret',
  storeTokens: 'memory',
});

const app = express();

app.use(express.json());

// Login: issue JWT
app.post('/login', async (req, res) => {
  const token = await auth.jwt.sign({ id: 'u1', role: 'admin' }, '2h', { res });
  res.json({ token });
});

// Protected route
app.get('/me', auth.jwt.protect(), (req, res) => {
  res.json({ message: `Welcome, ${req.user.id}` });
});

// Logout: revoke token
app.post('/logout', async (req, res) => {
  const token = auth.jwt.readCookie(req, 'auth_token');
  await auth.jwt.revoke(token);
  res.json({ success: true, message: 'Logged out' });
});

app.listen(3000, () => console.log('✅ Auth server running on port 3000'));

🧠 Notes

  • Works seamlessly with cookie-parser or built-in cookie reader.
  • Supports both stateful (Redis/Memory) and stateless (None) JWT modes.
  • Built-in cookie signing ensures secure browser sessions.
  • Middleware simplifies authentication guards in Express apps.

🔢 OTP (email / sms / telegram / whatsapp api / custom sender)

🔐 OTP Manager — auth-verify

The OTPManager handles one-time passwords (OTP) for multi-channel authentication:

  • ✅ Email
  • ✅ SMS
  • ✅ WhatsApp
  • ✅ Telegram Supports memory, Redis, or no storage, cooldowns, and max-attempt tracking.

📦 Import

const AuthVerify = require("auth-verify");
const auth = new AuthVerify();

// Access OTP manager
const otp = auth.otp; // internally uses OTPManager

⚙️ Constructor Options

| Option | Type | Default | Description | | ------------- | ------------- | -------------------------- | ------------------------------------------------- | | otpExpiry | string/number | 300 | OTP expiration time, e.g., "5m" or "30s" | | storeTokens | string | "memory" | Storage type: "memory", "redis", or "none" | | otpHash | string | "sha256" | Hashing algorithm for OTP (optional) | | sender | object | null | Email/SMS/WhatsApp/Telegram sender configuration | | redisUrl | string | "redis://localhost:6379" | Redis connection URL (if storeTokens = 'redis') |

⚙️ Sender Configuration

Email sender

Using Gmail
otp.sender({
    via: "email", // or "sms", "telegram", "whatsapp"
    service: "gmail", // email service
    sender: "[email protected]",
    pass: "your_app_password",
    host: "smtp.gmail.com",
    port: 587,
    secure: false
});

// or you can use otp.setSender({...});
Using SMTP service
otp.sender({
  via: "email", // or "sms", "telegram", "whatsapp"
  sender: "[email protected]",
  pass: "your_app_password",
  host: "smtp.gmail.com",
  port: 587,
  secure: false
})

SMS sender

📘 Auth-Verify SMS API — Full Guide

Auth-Verify supports sending OTPs via SMS using 30+ global SMS providers.

1️⃣ Initialize SMS Sender

Before sending SMS, you must configure your sender:

otp.sender({
  via: "sms",               // REQUIRED — "sms" or "email" or "telegram"
  provider: "twilio",       // REQUIRED — choose provider
  apiKey: process.env.TWILIO_SID,       // varies per provider
  apiSecret: process.env.TWILIO_TOKEN,  // varies per provider
  sender: "+15005550006",   // sender phone or ID
  mock: false               // optional: true = no real SMS sent
});
2️⃣ Send OTP
const smsResponse = await otp.send("+998901234567");
console.log(smsResponse);
✅ Example Response
{
  "status": "SENT",
  "provider": "Twilio",
  "to": "+998901234567"
}
3️⃣ Mock Mode for Testing
otp.sender({
  via: "sms",
  provider: "twilio",
  mock: true
});

Console output:

📱 [Mock SMS via twilio]
→ To: +998901234567
→ Message: Your OTP is 123456
5️⃣ Supported SMS Providers & Example Config

| Provider | Config Example | Notes | | ----------------- | -------------------------------------------------------- | ---------------------------- | | Twilio | apiKey = SID, apiSecret = TOKEN, sender = +15005550006 | Global | | Vonage / Nexmo | apiKey, apiSecret, sender | Global | | Infobip | apiKey, sender | Global / EU strong | | Eskiz | email, password, sender | Uzbekistan | | PlayMobile | apiKey, apiSecret, sender | Uzbekistan | | MSG91 | apiKey, templateId = apiSecret | India | | Telesign | apiKey, apiSecret | Global | | SMS.ru | apiKey | Russia | | TextLocal | apiKey, sender | India/UK | | ClickSend | apiKey, apiSecret, sender | Global | | Sinch | apiKey, apiSecret | Global | | Telnyx | apiKey, sender | Global | | NetGSM | apiKey, apiSecret, sender | Turkey | | KaveNegar | apiKey | Iran | | Unifonic | apiKey, sender | Saudi Arabia | | Alibaba Cloud SMS | apiKey, template_id, region, sender | China | | Firebase | client SDK only | OTP must be sent client-side | | CheapGlobalsms | apiKey, apiSecret, sender | Global | | Africa's Talking | apiKey, sender | Africa | | MessageBird | apiKey, sender | Global | | SMSAPI | apiKey, sender | Europe | | Clickatell | apiKey, sender | Global | | Plivo | apiKey, apiSecret, sender | Global | | Vibes | apiKey | US | | SMS Gateway Hub | apiKey, sender | India | | TextMagic | apiKey, apiSecret, sender | Global |

All providers use the same sendSMS helper, just change provider and API credentials. How to use this table:

// Using eskiz provider (for example)
otp.sender({
  provider: 'eskiz', // (see Provider column)
  email: "YOUR_EMAIL_HERE", // (see Config Example column)
  password: "YOUR_PASSWORD_HERE", // (see Config Example column)
  sender: "YOUR_SENDER_NAME_HERE" // (see Config Example column)
});
Error handling
try {
  const result = await auth.otp.send("+998901234567");
} catch (err) {
  console.error("SMS failed:", err.message);
}

Telegram sender

otp.sender({
  via: 'telegram',
  token: '123:ABC', // bot token
  // call auth.otp.setupTelegramBot(token) to start the bot
});

WhatsApp Business API

otp.sender({
  via: 'whatsapp',
  phoneId: "YOUR_PHONE_ID",
  token: "YOUR_WHATSAPP_TOKEN"
});

🪄 Generate OTP

otp.generate(6); // 6-digit OTP
  • Returns a numeric string
  • Supports callback style:
otp.generate(6, (err, code) => {
    console.log(code);
});
  • Chainable:
otp.generate(6).set("[email protected]");

💾 Store OTP

await otp.set("[email protected]");
  • Supports memory and Redis
  • Stores metadata: attempts, expiry, cooldown
  • Can also use callback style for memory storage

📤 Send OTP

await otp.send("[email protected]", {
    subject: "Your OTP Code",
    text: "Your OTP is 123456",
    html: "<b>123456</b>"
});

// or simply
await otp.send("[email protected]");

Supports channels: | via | Notes | | -------- | ---------------------------------------- | | email | Configured with Gmail/SMTP | | sms | Uses sendSMS helper or custom provider | | telegram | Sends OTP via bot, requires botToken | | whatsapp | Uses WhatsApp Business API |

Callback style:

otp.send("[email protected]", options, (err, info) => {
    if(err) console.error(err);
    else console.log(info);
});

🔑 Verify OTP

// Promise style
const result = await otp.verify("[email protected]", "123456");
//const result = await otp.verify({ check: "[email protected]", code: "123456" }); or you can use this style

// Callback style
otp.verify("[email protected]", "123456", (err, success) => {
    if(err) console.error(err.message);
    else console.log("✅ OTP verified");
});
  • Automatically deletes OTP after successful verification
  • Checks expiry and maximum attempts
  • Throws descriptive errors:
  • OTP expired
  • Invalid OTP
  • Max attempts reached

⏱ Cooldown

otp.cooldown("30s"); // cooldown before OTP can be resent
  • Accepts "30s", "2m", "1h", or milliseconds
  • Enforced in resend() method

🔄 Resend OTP

const code = await otp.resend("[email protected]");
  • Automatically generates a new OTP if expired
  • Updates cooldown
  • Sends via configured channel (email/SMS/WhatsApp)
  • Callback support:
otp.resend("[email protected]", (err, code) => {
    if(err) console.error(err.message);
    else console.log("Resent OTP:", code);
});

🤖 Telegram Integration

await otp.setupTelegramBot("YOUR_BOT_TOKEN");
  • Sets up a Telegram bot to send OTP
  • Users share their phone number in chat
  • OTP automatically sent to the shared number

📌 Private Methods (Internal)

  • #sendEmail(reciever, options) → Sends email OTP
  • #sendSMS(reciever, options) → Sends SMS OTP
  • #sendWhatsApp(reciever, options) → Sends WhatsApp OTP

Usually not called directly — use otp.send() instead.

🧩 Example Usage

const AuthVerify = require("auth-verify");
const auth = new AuthVerify({ otpExpiry: "5m", storeTokens: "memory" });

// Set sender
auth.otp.setSender({
    via: "email",
    service: "gmail",
    sender: process.env.EMAIL,
    pass: process.env.EMAIL_PASS
});

// Generate and send OTP
await auth.otp.send("[email protected]", { subject: "Verify your account" });

// Verify OTP
try {
    await auth.otp.verify({ check: "[email protected]", code: "123456" });
    console.log("✅ OTP verified!");
} catch (err) {
    console.error(err.message);
}

// Resend OTP if needed
const newCode = await auth.otp.resend("[email protected]");
console.log("Resent OTP:", newCode);

⚡ Notes

  • OTPManager is fully integrated into auth-verify wrapper
  • Supports multi-channel OTP with memory or Redis storage
  • Handles cooldowns, max attempts, and automatic expiry
  • Can be extended with custom sender functions

📝 AuthVerify TOTP API Guide

✅ TOTP (Time-based One Time Passwords) — Google Authenticator support

1️⃣ Generate TOTP Secret

Theory:
  • Generate a Base32 secret for a user.
  • Secret is required to generate TOTP codes in an authenticator app (Google Authenticator, Authy, etc.).
Code:
// GET /api/totp/secret
app.get("/api/totp/secret", (req, res) => {
  const secret = auth.totp.secret(); // Base32 secret
  res.json({ success: true, secret });
});
Usage:
const response = await fetch("http://localhost:3000/api/totp/secret");
const data = await response.json();
console.log(data.secret); // "JBSWY3DPEHPK3PXP"
Usage (with Auth-verify client):
const auth = new AuthVerify({ apiBase: "http://localhost:3000" });
const res = auth.get("/api/secret/totp/secret").data();
console.log(res.secret); // "JBSWY3DPEHPK3PXP"

2️⃣ Generate TOTP URI

Theory:
  • Convert secret into an otpauth:// URI for authenticator apps.
  • URI includes: secret, label (user email), issuer (app name), algorithm, digits, and period.
Code:
// POST /api/totp/uri
app.post("/api/totp/uri", (req, res) => {
  const { secret, label, issuer } = req.body;
  const uri = auth.totp.uri({ secret, label, issuer });
  res.json({ success: true, uri });
});
Usage:
const { uri } = await fetch("http://localhost:3000/api/totp/uri", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    secret: "JBSWY3DPEHPK3PXP",
    label: "[email protected]",
    issuer: "MyApp"
  })
}).then(r => r.json());

console.log(uri);
// otpauth://totp/MyApp:[email protected]?secret=...
Usage (with Auth-verify client):
const auth = new AuthVerify({ apiBase: "http://localhost:3000" });
const uri = auth.post("/api/totp/uri").data({secret: "JBSWY3DPEHPK3PXP", label: "[email protected]", issuer: "MyApp"});
console.log(uri); // otpauth://totp/MyApp:[email protected]?secret=...

3️⃣ Generate QR Code

Theory:
  • Convert TOTP URI into a QR code.
  • Users can scan QR code with their authenticator app.
Code:
// POST /api/totp/qrcode
app.post("/api/totp/qrcode", async (req, res) => {
  const { uri } = req.body;
  const qr = await auth.totp.qr(uri); // returns base64 data URL
  res.json({ success: true, qr });
});
Usage:
const { qr } = await fetch("http://localhost:3000/api/totp/qrcode", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ uri })
}).then(r => r.json());

document.getElementById("totp-qrcode").src = qr;
Usage (with Auth-verify client):
const auth = new AuthVerify({
  apiBase: "http://localhost:3000",
  qrEl: document.getElementById("totp-qrcode")
});

auth.get("/api/totp/qrcode").qr();

4️⃣ Verify TOTP Code

Theory:

  • Compare user-provided code with expected code.
  • Optional window allows ±1 or more steps to account for clock skew.

Code:

// POST /api/totp/verify
app.post("/api/totp/verify", (req, res) => {
  const { secret, code, window } = req.body;
  const valid = auth.totp.verify(secret, code, window);
  res.json({ success: true, valid });
});

Usage:

const userCode = prompt("Enter your TOTP code:");
const { valid } = await fetch("http://localhost:3000/api/totp/verify", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    secret: "JBSWY3DPEHPK3PXP",
    code: userCode
  })
}).then(r => r.json());

if(valid) alert("✅ Verified!");
else alert("❌ Invalid TOTP code");
Usage (with Auth-verify client):
const auth = new AuthVerify({ apiBase: "http://localhost:3000" });

const valid = auth.post("/api/totp/verify").verify(userCode);
if(valid) alert("✅ Verified!");
else alert("❌ Invalid TOTP code");

5️⃣ API Reference Table

| Endpoint | Method | Description | Payload | Response | | ------------------ | ------ | ----------------------------- | --------------------------- | ---------------------------------------------------- | | /api/totp/secret | GET | Generate a Base32 secret | None | { success: true, secret: "..." } | | /api/totp/uri | POST | Convert secret to otpauth URI | { secret, label, issuer } | { success: true, uri: "..." } | | /api/totp/qrcode | POST | Generate QR code from URI | { uri } | { success: true, qr: "data:image/png;base64,..." } | | /api/totp/verify | POST | Verify user TOTP code | { secret, code, window? } | { success: true, valid: true/false } |


🗝️ Passkey (WebAuthn)

🔑 Passkey Authentication — AuthVerify Frontend + Backend Guide

This guide explains how to integrate Passkey (WebAuthn) authentication using the AuthVerify ecosystem — including both:

  • 🧠 Backend: PasskeyManager (Node.js)
  • 💻 Frontend: window.AuthVerify wrapper (Browser)

⚙️ 1. Backend Setup (Node.js)

Import and configure AuthVerify:

const express = require("express");
const AuthVerify = require("auth-verify");
const app = express();

app.use(express.json());

const auth = new AuthVerify({
  rpName: "AuthVerifyApp",   // Display name in browser prompt
  storeTokens: "memory",     // or "redis"
  passExp: "2m",             // Challenge expiration
});

🧩 2. Passkey Registration API

POST /api/register/start

Generate registration challenge for a new user.

app.post("/api/register/start", async (req, res) => {
  const user = req.body.user; // e.g. { id: "u123", username: "john_doe" }
  await auth.passkey.register(user);
  res.json(auth.passkey.getOptions());
});

auth.issue() can be used for saving passkey in any device

POST /api/register/finish

Verify attestation and save credential.

app.post("/api/register/finish", async (req, res) => {
  const result = await auth.passkey.finish(req.body);
  res.json(result);
});

Example successful response:

{
  "status": "ok",
  "user": {
    "id": "u123",
    "username": "john_doe",
    "credentials": [
      {
        "id": "AaBbCcDdEe...",
        "publicKey": "-----BEGIN PUBLIC KEY-----...",
        "signCount": 0
      }
    ]
  },
  "credentialId": "AaBbCcDdEe..."
}

🔐 3. Passkey Login API

POST /api/login/start

Generate login challenge for existing user.

app.post("/api/login/start", async (req, res) => {
  const user = req.body.user; // same user object used at registration
  await auth.passkey.login(user);
  res.json(auth.passkey.getOptions());
});
POST /api/login/finish

Verify user assertion (digital signature).

app.post("/api/login/finish", async (req, res) => {
  const result = await auth.passkey.finish(req.body);
  res.json(result);
});

Successful login:

{
  "status": "ok",
  "user": { "id": "u123", "username": "john_doe" }
}

💻 4. Frontend Integration (Browser)

Include your frontend wrapper (already built as window.AuthVerify):

<script src="https://cdn.jsdelivr.net/gh/jahongir2007/auth-verify/auth-verify.client.js"></script>
<script>
  const auth = new AuthVerify({ apiBase: "http://localhost:3000" });
</script>

⚡ 5. Frontend Methods

🧱 .post(url) / .get(url)

Set endpoint for POST/GET requests before calling .data().

⚙️ .data(payload)

Send JSON to backend and return response.

🧠 Step Breakdown

1️⃣ Frontend → Backend: /api/register/start

Sends { user } and gets WebAuthn challenge/options.

2️⃣ Browser:

Calls navigator.credentials.create({ publicKey }) Prompts user for biometric or security key registration.

3️⃣ Frontend → Backend: /api/register/finish

Sends credential data (clientDataJSON, attestationObject, etc.)

4️⃣ Backend:

Validates and stores public key in user credentials.

🧠 Step Breakdown

1️⃣ Frontend → Backend: /api/login/start

Sends { user, login: true } to get challenge and allowCredentials.

2️⃣ Browser:

Calls navigator.credentials.get({ publicKey }).

3️⃣ Frontend → Backend: /api/login/finish

Sends credential signature data (authenticatorData, signature, etc.)

4️⃣ Backend:

Verifies signature using stored public key.

🧠 8. Quick Reference

| Layer | Method | Description | | -------- | -------------------------------- | ---------------------------- | | Backend | passkey.register(user) | Start registration | | Backend | passkey.getOptions() | Return challenge for browser | | Backend | passkey.finish(clientResponse) | Finish registration/login |

✅ 9. Notes & Best Practices

  • Use HTTPS in production (navigator.credentials requires secure origin)
  • Always send real user.id (string, not numeric)
  • Store public keys securely in DB after registration
  • Set realistic expiration time for passkey challenges (passExp)
  • Combine with your JWTManager for session generation after successful login

🔑 AuthVerify Client Guide

This client is designed to interact with the backend AuthVerify API for passkeys / WebAuthn credentials. It does not require body-parser or any server-side logic on the frontend.

📦 Import

<!-- ✅ Import auth-verify client -->
  <script src="https://cdn.jsdelivr.net/gh/jahongir2007/auth-verify/auth-verify.client.js"></script>

⚙️ Initialization

const auth = new AuthVerify({
  apiBase: "http://localhost:3000",
  qrEl: document.getElementById("qr") // optional, for QR codes
});

| Option | Type | Default | Description | | --------- | ------------------ | ------------------------- | ------------------------------------ | | apiBase | string | 'http://localhost:3000' | Backend API base URL | | qrEl | HTMLImageElement | null | Optional element to display QR codes |

📬 Methods

1️⃣ post(url)

Sets the POST endpoint for the next request.

auth.post("/start-passkey");

2️⃣ get(url)

Sets the GET endpoint for the next request.

auth.get("/fetch-qr");

3️⃣ qr()

Fetches a QR code from the backend and renders it in qrEl.

await auth.get("/fetch-qr").qr();
Behavior:
  • If qrEl exists, its src will be set to the QR image returned by the backend.
  • Logs an error if no QR or fetch fails.

4️⃣ data(payload)

Sends a POST request with JSON payload to the set endpoint.

const response = await auth.post("/verify-otp").data({ code: "123456" });
console.log(response);

5️⃣ header()

Returns an authorization header if jwt exists.

const headers = auth.header();
// { Authorization: 'Bearer <token>' }

6️⃣ verify(code)

Shortcut for sending OTP / code to backend.

const result = await auth.verify("123456");

7️⃣ base64urlToUint8Array(base64url)

Helper to decode Base64URL strings (used for WebAuthn challenges).

const arr = auth.base64urlToUint8Array("BASE64URL_STRING");

8️⃣ issue(publicKey)

Creates a WebAuthn credential on the client (passkey).

// 1️⃣ Get registration options from backend
const publicKey = await auth.post("/start-passkey").data({ user: { id: "user123", name: "Alice" } });

// 2️⃣ Issue credential in browser
const credentialData = await auth.issue(publicKey);

// 3️⃣ Send credential back to backend
const result = await auth.post("/finish-passkey").data(credentialData);
console.log(result);

| Step | Description | | ---- | ----------------------------------------------------------------------------------- | | 1 | Fetch publicKey options from backend | | 2 | Decode challenge & user ID, create credential with navigator.credentials.create() | | 3 | Convert ArrayBuffers to Base64 and return structured object | | 4 | Send credential to backend via post() |

Returned object:
{
  id: "...",
  rawId: "...",
  type: "public-key",
  response: {
    clientDataJSON: "...",
    attestationObject: "..."
  }
}

🧪 Example Full Flow

(async () => {
  const auth = new AuthVerify({ apiBase: "http://localhost:3000", qrEl: document.getElementById("qr") });

  // Display QR from backend
  await auth.get("/fetch-qr").qr();

  // Create a passkey
  const publicKey = await auth.post("/start-passkey").data({ user: { id: "user123", name: "Alice" } });
  const credential = await auth.issue(publicKey);

  // Send back to backend
  const result = await auth.post("/finish-passkey").data(credential);
  console.log(result);
})();

9️⃣ Example HTML

<img id="qrImage" />
<div id="response"></div>
<button id="getQRBtn">Get QR</button>
<button id="sendBtn">Send Data</button>

<script src="https://cdn.jsdelivr.net/gh/jahongir2007/auth-verify/auth-verify.client.js"></script>
<script>
const qrImage = document.getElementById('qrImage');
const responseDiv = document.getElementById('response');

const auth = new AuthVerify({ apiBase: 'http://localhost:3000', qrEl: qrImage });

document.getElementById('getQRBtn').addEventListener('click', () => auth.get('/api/qr').qr());

document.getElementById('sendBtn').addEventListener('click', async () => {
  const payload = { name: 'Jahongir' };
  const result = await auth.post('/api/sign-jwt').data(payload);
  responseDiv.textContent = JSON.stringify(result, null, 2);
});
</script>

10️⃣ Tips for Developers

  • Always call auth.get('/api/qr').qr() after page loads
  • Use auth.header() for any authenticated request
  • Backend must provide endpoints for /api/qr, /api/verify-totp, /api/sign-jwt
  • Make sure backend endpoints return raw WebAuthn options (challenge, user, allowCredentials) in Base64URL format.
  • user.id and challenge must be Base64URL encoded on backend.
  • JWT storage is automatic if backend returns token.

🔐 OAuth Manager — auth-verify

The OAuthManager in auth-verify provides an easy and unified way to integrate popular social logins such as Google, GitHub, Facebook, Twitter (X), LinkedIn, and others. Each provider offers two main methods:

  • redirect(res) → Redirects users to provider’s authorization page
  • callback(code) → Exchanges authorization code for access token and retrieves user data

📦 Import

const AuthVerify = require("auth-verify");
const auth = new AuthVerify();

Then access:

auth.oauth

⚙️ Constructor Options

| Option | Type | Default | Description | | ----------- | -------- | ------- | -------------------------------------------- | | providers | object | {} | Register custom OAuth providers dynamically. |

🧩 Supported Providers

The following providers are built-in and ready to use:

| Provider | Method | OAuth Version | | ----------- | ------------------------ | ------------- | | Google | auth.oauth.google() | v2 | | Facebook | auth.oauth.facebook() | v2 | | GitHub | auth.oauth.github() | v2 | | Twitter (X) | auth.oauth.x() | v2 | | LinkedIn | auth.oauth.linkedin() | v2 | | Apple | auth.oauth.apple() | v2 | | Discord | auth.oauth.discord() | v2 | | Slack | auth.oauth.slack() | v2 | | Microsoft | auth.oauth.microsoft() | v2 | | Telegram | auth.oauth.telegram() | Deep Link | | WhatsApp | auth.oauth.whatsapp() | Deep Link | | Reddit | auth.oauth.reddit() | v2 | | Yandex | auth.oauth.yandex() | v2 | | Tumblr | auth.oauth.tumblr() | v2 | | Mail.ru | auth.oauth.mailru() | v2 | | VK | auth.oauth.vk() | v2 | | Yahoo | auth.oauth.yahoo() | v2 |

🪄 Common Usage

Step 1: Redirect user to provider

app.get("/auth/google", (req, res) => {
  auth.oauth.google({
    clientId: process.env.GOOGLE_CLIENT_ID,
    redirectUri: "http://localhost:3000/auth/google/callback"
  }).redirect(res);
});

Step 2: Handle callback and get user data

app.get("/auth/google/callback", async (req, res) => {
  try {
    const data = await auth.oauth.google({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      redirectUri: "http://localhost:3000/auth/google/callback"
    }).callback(req.query.code);

    res.json({ success: true, user: data });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

🌍 Provider Reference

Each provider returns { redirect, callback }. Below are provider-specific examples and scopes.

🟢 Google Login

Scopes: openid email profile

auth.oauth.google({
  clientId,
  clientSecret,
  redirectUri
});

Returns user:

{
  "email": "[email protected]",
  "name": "John Doe",
  "picture": "https://...",
  "access_token": "ya29.a0..."
}

🔵 Facebook Login

Scopes: email, public_profile

auth.oauth.facebook({ clientId, clientSecret, redirectUri });

Returns user:

{
  "id": "123456789",
  "name": "John Doe",
  "email": "[email protected]",
  "picture": { "data": { "url": "https://..." } },
  "access_token": "EAAJ..."
}

⚫ GitHub Login

Scopes: user:email

auth.oauth.github({ clientId, clientSecret, redirectUri });

Returns user:

{
  "login": "johndoe",
  "id": 123456,
  "email": "[email protected]",
  "avatar_url": "https://github.com/images/...",
  "access_token": "gho_..."
}

🐦 Twitter (X) Login

Scopes: tweet.read users.read offline.access

auth.oauth.x({ clientId, clientSecret, redirectUri });

Returns user:

{
  "data": { "id": "12345", "name": "John Doe", "username": "johndoe" },
  "access_token": "2.abc..."
}

💼 LinkedIn Login

Scopes: r_liteprofile r_emailaddress

auth.oauth.linkedin({ clientId, clientSecret, redirectUri });

Returns user:

{
  "id": "A1B2C3D4",
  "name": "John Doe",
  "email": "[email protected]",
  "access_token": "AQW..."
}

🍎 Apple Login

Scopes: name email

auth.oauth.apple({ clientId, clientSecret, redirectUri });

Returns:

{
  "access_token": "eyJraWQiOi...",
  "id_token": "...",
  "refresh_token": "...",
  "expires_in": 3600
}

💬 Discord Login

Scopes: identify email

auth.oauth.discord({ clientId, clientSecret, redirectUri });

Returns:

{
  "id": "123456789",
  "username": "john",
  "email": "[email protected]",
  "access_token": "abc123..."
}

🧰 Slack Login

Scopes: identity.basic identity.email

auth.oauth.slack({ clientId, clientSecret, redirectUri });

Returns:

{
  "ok": true,
  "access_token": "xoxp-...",
  "authed_user": { "id": "U1234", "scope": "identity.basic,identity.email" }
}

🪟 Microsoft Login

Scopes:* User.Read

auth.oauth.microsoft({ clientId, clientSecret, redirectUri });

Returns token:

{
  "token_type": "Bearer",
  "expires_in": 3599,
  "access_token": "EwB4A8l6..."
}

💬 Telegram Login (Deep Link)

auth.oauth.telegram({ botId: "YourBotName", redirectUri });

Note: Telegram handles authentication through deep links. Returns:

{ "message": "Telegram login uses deep link auth" }

🟢 WhatsApp Login (Deep Link)

auth.oauth.whatsapp({ phoneNumberId: "1234567890", redirectUri });

Note: Usually handled via QR code or direct chat. Returns:

{ "message": "WhatsApp login uses QR/deep link auth" }

🧱 Reddit Login

Scopes: identity

auth.oauth.reddit({ clientId, clientSecret, redirectUri });

Returns user:

{
  "name": "johndoe",
  "id": "t2_123abc",
  "icon_img": "https://styles.redditmedia.com/...",
  "access_token": "abc123..."
}

🟥 Yandex Login

Scopes: login:email login:info

auth.oauth.yandex({ clientId, clientSecret, redirectUri });

Returns user:

{
  "id": "1234567",
  "display_name": "John Doe",
  "emails": ["[email protected]"],
  "default_email": "[email protected]",
  "access_token": "y0_AgAAA..."
}

🌐 Tumblr Login

Scopes: basic write offline_access

auth.oauth.tumblr({ clientId, clientSecret, redirectUri });

Returns user:

{
  "name": "johndoe",
  "blogs": [{ "name": "myblog", "title": "My Tumblr Blog" }],
  "access_token": "xyz..."
}

✉️ Mail.ru Login

Scopes: userinfo.email

auth.oauth.mailru({ clientId, clientSecret, redirectUri });

Returns user:

{
  "id": "123456",
  "email": "[email protected]",
  "name": "John Doe",
  "access_token": "abc123..."
}

🧍 VK (VKontakte) Login

Scopes: email

auth.oauth.vk({ clientId, clientSecret, redirectUri });

Returns user:

{
  "id": 987654,
  "first_name": "John",
  "last_name": "Doe",
  "email": "[email protected]",
  "access_token": "vk1.a.abc..."
}

💜 Yahoo Login

Scopes: openid profile email

auth.oauth.yahoo({ clientId, clientSecret, redirectUri });

Returns user:

{
  "sub": "12345",
  "email": "[email protected]",
  "name": "John Doe",
  "access_token": "y0_AgA..."
}

🧩 Custom OAuth Provider

You can register your own provider logic:

auth.oauth.register("custom", ({ clientId, clientSecret, redirectUri }) => ({
  redirect(res) {
    res.redirect("https://custom-oauth.com/auth");
  },
  async callback(code) {
    return { code, message: "Custom provider handled!" };
  },
}));

// Usage:
auth.oauth.use("custom", { clientId, clientSecret, redirectUri });

🔒 Error Handling

Each callback() method may throw:

  • OAuth Error: invalid_client
  • OAuth Error: invalid_grant
  • OAuth Error: unauthorized_client
  • OAuth Error: access_denied Always wrap in try/catch:
try {
  const user = await auth.oauth.google(...).callback(code);
} catch (err) {
  console.error("Login failed:", err.message);
}

💡 Notes

  • Every provider uses OAuth 2.0 Authorization Code flow.
  • redirect(res) is server-side only (Node.js Express compatible).
  • Works perfectly inside your auth-verify unified wrapper.

💌 Magiclink (Passwordless login) (v1.8.0+)

The Magic Link Manager allows developers to implement secure, passwordless login using email-based links. Built directly into the AuthVerify SDK, it supports Gmail, custom SMTP, and token storage via Memory or Redis.

🚀 Basic Setup

const AuthVerify = require('auth-verify');

const auth = new AuthVerify({
  mlSecret: 'super_secret_key',
  mlExpiry: '5m',
  appUrl: 'http://localhost:3000',
  storeTokens: 'memory'
});

⚙️ Configure Magic Link Sender

Before sending links, you must set up your email transport.

Gmail Example

await auth.magic.sender({
  service: 'gmail',
  sender: '[email protected]',
  pass: 'your_gmail_app_password'
});

Custom SMTP Example

await auth.magic.sender({
  host: 'smtp.mailgun.org',
  port: 587,
  secure: false,
  sender: '[email protected]',
  pass: 'your_smtp_password'
});

✅ Both Gmail and any SMTP provider are supported. Use app passwords or tokens instead of your real password!

📩 Send Magic Link

Send a secure, expiring link to the user’s email:

await auth.magic.send('[email protected]', {
  subject: 'Your Secure Login Link ✨',
  html: `<p>Click below to sign in:</p>
         <a href="{{link}}">Login Now</a>`
});

The {{link}} placeholder will automatically be replaced with the generated magic link.

🪄 Generate Magic Link Manually

If you just want to create a link (not send it yet):

const token = await auth.magic.generate('[email protected]');
console.log(token);

Then make your own URL:

const link = `http://localhost:3000/auth/verify?token=${token}`;

🔐 Verify Magic Link

Typically used in your backend /auth/verify route:

app.get('/auth/verify', async (req, res) => {
  const { token } = req.query;
  try {
    const user = await auth.magic.verify(token);
    res.json({ success: true, user });
  } catch (err) {
    res.status(400).json({ success: false, message: err.message });
  }
});

🧠 How It Works

  1. auth.magic.generate() → creates a short-lived JWT with the user’s email.
  2. auth.magic.send() → sends a secure login link by email.
  3. auth.magic.verify() → decodes & validates the token, optionally checks store.

💾 Storage Options

| Mode | Description | Best For | | ------------------ | -------------------- | ------------------------------ | | memory (default) | Uses in-memory Map() | Single server / small projects | | redis | Uses Redis with TTL | Scalable, multi-server apps |

Example using Redis:

const auth = new AuthVerify({
  storeTokens: 'redis',
  redisUrl: 'redis://localhost:6379'
});

🧰 Callback Support

You can also use Node-style callbacks if you prefer:

auth.magic.send('[email protected]', (err) => {
  if (err) console.error('❌ Failed to send link:', err);
  else console.log('✅ Magic link sent!');
});

🌍 Example Express Integration

const express = require('express');
const bodyParser = require('body-parser');
const { AuthVerify } = require('auth-verify');

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

const auth = new AuthVerify({
  mlSecret: 'supersecretkey',
  appUrl: 'http://localhost:3000',
  storeTokens: 'memory'
});

auth.magic.sender({
  service: 'gmail',
  sender: '[email protected]',
  pass: 'your_app_password'
});

// Send link
app.post('/auth/send', async (req, res) => {
  const { email } = req.body;
  await auth.magic.send(email);
  res.json({ message: 'Magic link sent!' });
});

// Verify link
app.get('/auth/verify', async (req, res) => {
  try {
    const user = await auth.magic.verify(req.query.token);
    res.json({ message: 'Login successful!', user });
  } catch (err) {
    res.status(400).json({ message: err.message });
  }
});

app.listen(3000, () => console.log('🚀 Server running on port 3000'));

🧾 Summary

| Feature | Supported | | -------------------------- | --------- | | Gmail & SMTP | ✅ | | Memory & Redis Token Store | ✅ | | Token Expiry | ✅ | | Callback & Promise APIs | ✅ | | HTML Custom Email | ✅ |

⚡ Future Vision

auth.magic is built for modern SaaS, fintech, and crypto apps that need passwordless, secure, and user-friendly authentication.


Telegram integration

There are two ways to use Telegram flow:

  1. Use the built-in senderConfig.via = 'telegram' and call auth.otp.setupTelegramBot(botToken) — this starts a polling bot that asks users to share their phone via /start, and then matches the phone to in-memory/Redis OTP records and replies with the code.

  2. Developer-supplied custom sender (see below) — you can create your own bot and call it from auth.use(...).send(...) or register via auth.register.sender().

Important: Only one bot using long polling must be running per bot token — if you get 409 Conflict it's because another process or instance is already polling that bot token.


Developer extensibility (custom senders)

You can register custom senders and use them:

// register a named sender function
auth.register.sender('consoleOtp', async ({ to, code }) => {
  console.log(`[DEV SEND] send to ${to}: ${code}`);
});

// use it later (chainable)
await auth.use('consoleOtp').send({ to: '+998901234567', code: await auth.otp.generate(5).code });

When a custom sender is registered, auth.otp.message() will first attempt the customSender before falling back to built-in providers.


📝 SessionManager API Documentation - auth-verify

The session manager of auth-verify provides a simple way to create, verify, and destroy user sessions in either memory or Redis storage.

Import

const AuthVerify = require('auth-verify');
const auth = new AuthVerify({ storeTokens: 'redis', redisUrl: "redis://localhost:6379" });
Options:

| Option | Type | Default | Description | | ------------- | ------ | -------------------------- | --------------------------------------------------------- | | storeTokens | string | 'memory' | Storage type for sessions: 'memory' or 'redis' | | redisUrl | string | "redis://localhost:6379" | Redis connection URL (required if storeTokens: 'redis') |

Methods

1️⃣ create(userId, options)

Create a new session for a user. Parameters: | Name | Type | Required | Description | | | --------- | ------ | -------- | --------------------------------------- | --------- | | userId | string | ✅ | Unique ID of the user | | | options | object | ❌ | Optional settings: { expiresIn: number | string } |

expiresIn formats:

  • Number → seconds
  • String → "30s", "5m", "2h", "1d"
Returns:

Promise<string> → The session ID (UUID)

Example:
// Memory storage
const auth = new AuthVerify({ storeTokens: 'memory' });
const sessionId = await auth.session.create("user123", { expiresIn: "2h" });
console.log(sessionId); // "550e8400-e29b-41d4-a716-446655440000"

2️⃣ verify(sessionId)

Verify if a session is valid.

Parameters:

| Name | Type | Required | Description | | ----------- | ------ | -------- | ------------------------ | | sessionId | string | ✅ | The session ID to verify |

Returns:

Promise<string> → Returns the userId if session is valid

Throws:
  • "Session not found or expired"
  • "Session expired"
Example:
const userId = await auth.session.verify(sessionId);
console.log(userId); // "user123"

3️⃣ destroy(sessionId)

Invalidate (destroy) a session manually.

Parameters:

| Name | Type | Required | Description | | ----------- | ------ | -------- | ------------------------- | | sessionId | string | ✅ | The session ID to destroy |

Returns:

Promise<void>

Example:
await auth.session.destroy(sessionId);
console.log("Session destroyed");

Notes & Best Practices

  • Memory storage is fast but not persistent across server restarts. Use Redis in production.
  • Always verify session before allowing access to protected routes.
  • Optionally, combine with JWT or OTP for multi-layered authentication.
  • Use expiresIn wisely — shorter times improve security but may require more frequent re-login.

🔐 CryptoManager API Guide

It supports both PBKDF2 and scrypt algorithms for password or data hashing.

🚀 Overview

The CryptoManager class helps developers easily hash and verify passwords or any sensitive data using strong cryptographic functions. It supports both Promise and callback styles.

🧩 Import and Setup

const AuthVerify = require('auth-verify');

// Default: pbkdf2 algorithm
const auth = new AuthVerify({
  hashAlg: 'pbkdf2', // or 'scrypt'
  iterations: 100000,
  keyLen: 64
});

🔨 1️⃣ Hash Data

Method

async hash(data, [callback])

Description

Hashes a string (like a password) using the specified algorithm and salt. You can use Promise or callback style.

Parameters

| Name | Type | Description | | ---------- | ----------- | -------------------------------------------- | | data | string | The input data to hash (e.g. password) | | callback | function? | Optional Node-style callback (err, result) |

Returns

An object containing:

{
  hashAlg: "pbkdf2" | "scrypt",
  salt: "<random hex string>",
  hash: "<hashed data in hex>"
}

Example (Promise)

const result = await auth.crypto.hash("myPassword123");
console.log(result);
// { hashAlg: 'pbkdf2', salt: '...', hash: '...' }

Example (Callback)

auth.crypto.hash("myPassword123", (err, result) => {
  if (err) return console.error(err);
  console.log(result);
});

🔍 2️⃣ Verify Data

Method

async verify(data, { hashAlg, salt, hash }, [callback])

Description

Verifies whether a given input matches a stored hash.

Parameters

| Name | Type | Description | | ------------------------- | ----------- | --------------------------------------------- | | data | string | The plaintext input (e.g. user password) | | { hashAlg, salt, hash } | object | The hash object from .hash() | | callback | function? | Optional Node-style callback (err, isValid) |

Returns

A boolean value:

  • true → data matches
  • false → mismatch

Example (Promise)

const result = await cryptoManager.hash("secret123");
const isValid = await cryptoManager.verify("secret123", result);
console.log(isValid); // true

Example (Callback)

const original = await cryptoManager.hash("secret123");

cryptoManager.verify("secret123", original, (err, valid) => {
  if (err) throw err;
  console.log(valid); // true
});

📊 3️⃣ Summary Table

| Method | Description | Returns | Async | | --------------------------------------------------- | ----------------------------------- | ------------------------- | ----- | | hash(data, [callback]) | Hashes input using PBKDF2 or scrypt | { hashAlg, salt, hash } | ✅ | | verify(data, { hashAlg, salt, hash }, [callback]) | Verifies input against hash | boolean | ✅ |

🧠 Notes

  • Both PBKDF2 and scrypt are strong, salted, one-way hashing algorithms.
  • Use PBKDF2 for compatibility; use scrypt for better memory-hard protection.
  • Salt ensures that each hash output is unique even for identical inputs.
  • The default iteration count (100,000) is secure but can be increased for stronger protection.

🧪 Example Full Flow

(async () => {
  const manager = new CryptoManager({ hashAlg: 'scrypt' });

  // Hash password
  const hashData = await manager.hash('MyStrongPassword');
  console.log('Stored hash:', hashData);

  // Verify password
  const match = await manager.verify('MyStrongPassword', hashData);
  console.log('Password valid:', match);
})();

Helpers

helpers/helper.js exposes utility functions used by managers:

  • generateSecureOTP(length, hashAlgorithm) — returns secure numeric OTP string
  • parseTime(strOrNumber) — converts '1h' | '30s' | number into milliseconds
  • resendGeneratedOTP(params) — helper to send email via nodemailer (used by resend)
  • sendSMS(params) — helper for sending SMS using supported providers or mock

Error handling and notes

  • Many methods support both callback and Promise (async/await) styles. When using Redis store, prefer async/await (callback variants intentionally return an error when Redis is selected).
  • OTP storage keys are the user identifier you pass (email or phone number). Keep identifiers consistent.
  • Be careful when using Telegram polling: do not run two instances with polling true for the same bot token (use webhooks or a single process).
  • When configuring SMTP (non-Gmail), provide host, port and secure in setSender().

Suggested folder structure

auth-verify/
├─ README.md
├─ package.json
├─ index.js         // exports AuthVerify
├─ src/
│  ├─ jwt/
|  |  ├─ index.js
|  |  ├─ cookie/index.js
│  ├─ /otp/index.js
│  ├─ /magiclink/index.js
│  ├─ /crypto/index.js
│  ├─ totp/
|  |  ├─ index.js
|  |  ├─ base32.js
│  ├─ /session/index.js
|  ├─ /oauth/index.js
│  └─ helpers/helper.js
├─ rest-api/
│  ├─ public/index.html
│  ├─ index.js
├─ babel.config.js
├─ auth-verify.client.js

Contributing & License

Contributions welcome! Open issues / PRs for bugs, improvements, or API suggestions.

MIT © 2025 — Jahongir Sobirov