node-less-otp
TypeScript icon, indicating that this package has built-in type declarations

0.0.8 • Public • Published

node-less-otp

A super lightweight Node.js stateless authentication library for generating and verifying one-time passwords (OTPs) without the database interaction and additional dependencies. TS is fully supported out of the box.

Table of Contents

Installation

You can install the node-less-otp library via npm:

npm install node-less-otp

Usage

To use the node-less-otp library, import the class and create an instance by passing your configuration. You can then generate and verify OTPs.

import LessOtp from "node-less-otp";

const otp = new LessOtp({
  secretSalt: "your_secret_salt", // Optional
  algorithm: "aes-256-cbc", // Optional
  ivLength: 16, // Optional
  enableSet: false, // Optional, not recommended (default: true)
});

API Documentation

Example Use Case

Diagram

LessOtpConfig

The configuration for the LessOtp instance:

Parameter Type Description
secretSalt string Optional secret salt used for encryption (if left blank, the random key is generated).
algorithm string Optional encryption algorithm (default: 'aes-256-cbc').
ivLength number Optional initialization vector length (default: 16).
enableSet boolean Optional flag that indicates whether to enable the OTP hash set to ensure each code is only used once (enabled by default, setting to false is not recommended).

GenerateOptions

Options for OTP generation:

Parameter Type Description
template string Optional template for OTP generation (see examples).
ttl number Optional time-to-live in seconds for the generated OTP (default: Infinity).

LessOtp Class

constructor

Creates an instance of the LessOtp class.

const otp = new LessOtp(config: LessOtpConfig);

gen

Generates an OTP based on a unique identifier and generation options.

const { otp, hash } = await otp.gen(id: string, options: GenerateOptions);
  • Parameters:

    • id: Unique identifier (e.g., phone number, email, username).
    • options: Generation options.
  • Returns: An object containing the generated OTP and its encrypted hash.

verify

Verifies the OTP by comparing it with the decrypted OTP hash.

const isValid = otp.verify(id: string, hash: string, submitted: string);
  • Parameters:

    • id: Unique identifier.
    • hash: Encrypted OTP hash.
    • submitted: Submitted OTP to verify.
  • Returns: true if the OTP is valid; otherwise, false.

Data

The data returned after generating an OTP (internal type, you can ignore it in this context):

Parameter Type Description
otp string The generated OTP.
expiresAt number Timestamp indicating when the OTP expires.

Examples

Generating an OTP

Example 1: Numeric OTP

const otp = new LessOtp({ secretSalt: "your_secret_salt" });

const { otp: generatedOtp, hash } = await otp.gen("user@example.com", {
  template: "N{6}",
  ttl: 300,
});
console.log("Generated Numeric OTP:", generatedOtp); // e.g., 491945
console.log("Encrypted Hash:", hash);

Example 2: Alphanumeric OTP

const { otp: generatedOtp, hash } = await otp.gen("user@example.com", {
  template: "A{8}",
  ttl: 300,
});
console.log("Generated Alphanumeric OTP:", generatedOtp); // e.g., 1aB2cD3e
console.log("Encrypted Hash:", hash);

Example 3: Mixed-case Letters with Numbers

const { otp: generatedOtp, hash } = await otp.gen("user@example.com", {
  template: "M{4}-N{2}",
  ttl: 300,
});
console.log("Generated Mixed-case OTP:", generatedOtp); // e.g., AbcD-12
console.log("Encrypted Hash:", hash);

Example 4: Custom Template

const { otp: generatedOtp, hash } = await otp.gen("user@example.com", {
  template: "N{2}-M{3}-U{2}",
  ttl: 300,
});
console.log("Generated Custom OTP:", generatedOtp); // e.g., 12-abc-XY
console.log("Encrypted Hash:", hash);

Verifying an OTP

const isValid = otp.verify("user@example.com", hash, "832-059");
console.log("Is OTP valid?", isValid);

Example of use with Express.js

const express = require("express");
const LessOtp = require("less-otp");

const PORT = 3000;

const app = express();
const auth = new LessOtp({
  // options
});

app.use(express.json());

// Request OTP endpoint
app.post("/request-otp", async (req, res) => {
  const { email } = req.body;

  if (!email) {
    return res.status(400).json({ error: "Email is required" });
  }

  try {
    const { otp, hash } = auth.gen(email, {
      template: "N{3}-N{3}", // 912-753
      ttl: 300, // 5 min
    });

    // Example of sending via Nodemailer
    const transporter = createTransport({
      service: "Gmail",
      host: "smtp.gmail.com",
      port: 465,
      secure: true,
      auth: {
        user: "youraddress@gmail.com",
        pass: "yourpassword",
      },
    });

    const mailOptions = {
      from: "youraddress@gmail.com",
      to: email,
      subject: "OTP Code",
      text: `Your OTP code is: ${otp}`,
    };

    const info = await transporter.sendMail(mailOptions);
    console.log(info);

    // Return hash in response
    res.json({ hash });
  } catch (error) {
    console.error("Error generating OTP:", error);
    res.status(500).json({ error: "An error occurred" });
  }
});

// Verify OTP endpoint
app.post("/verify-otp", (req, res) => {
  const { email, otp, hash } = req.body;

  if (!email || !otp || !hash) {
    res.status(400).json({ error: "Email, OTP, and hash are required" });
    return;
  }

  const isValid = auth.verify(email, hash, otp);

  if (!isValid) {
    res.status(401).json({ error: "Invalid OTP or OTP has expired" });
    return;
  }

  res.json({ message: "OTP verified successfully" });
});

app.listen(PORT, () => {
  console.log(`Server is running on ${PORT}`);
});

Changelog

[0.0.8] - 2024-11-05

Minor fix

[0.0.7] - 2024-11-05

Fixed: Types and exports

Updated: package.json

[0.0.6] - 2024-11-05

Added: Babel transpiler and Rollup Terser plugin to reduce dist size.

Updated: README.md

[0.0.5] - 2024-11-05

Added: Unit tests using Vitest.

Added: New enableSet flag in the class constructor to control whether OTPs should be stored in a hash set, ensuring that each OTP can only be used once (defaults to true).

Usage: To disable storing OTPs in the hash set (not recommended), set enableSet to false when initializing the class:

const lessOtp = new LessOtp({ enableSet: false });

Updated: secretSalt is now optional and, if not provided, will be generated automatically with a random length between 32 and 64 characters (16 to 32 bytes).

Updated: README.md

Code clean up

License

This project is licensed under the Apache-2.0 License.

Package Sidebar

Install

npm i node-less-otp

Weekly Downloads

3

Version

0.0.8

License

Apache-2.0

Unpacked Size

32.3 kB

Total Files

10

Last publish

Collaborators

  • maxonlinux