Skip to content

A lightweight Node.js library for generating and verifying one-time passwords (OTPs) without the database interaction and additional dependencies.

License

Notifications You must be signed in to change notification settings

maxonlinux/node-less-otp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

node-less-otp

A 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("[email protected]", {
  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("[email protected]", {
  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("[email protected]", {
  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("[email protected]", {
  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("[email protected]", 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: "[email protected]",
        pass: "yourpassword",
      },
    });

    const mailOptions = {
      from: "[email protected]",
      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.

About

A lightweight Node.js library for generating and verifying one-time passwords (OTPs) without the database interaction and additional dependencies.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published