Skip to content

ekaone/nano-otp

Repository files navigation

@ekaone/nano-otp

A tiny, zero-dependency One-Time Password (OTP) library for JavaScript and TypeScript.

@ekaone/nano-otp is designed to be lightweight, secure, and easy to integrate into modern applications. It uses Node.js built-in crypto for cryptographically secure random generation — no external dependencies required.

⚠️ Status: Under Active Development APIs and features may change before v1.0.0. Track progress at: https://github.com/ekaone/nano-otp


Installation

# pnpm
pnpm add @ekaone/nano-otp

# npm
npm install @ekaone/nano-otp

# yarn
yarn add @ekaone/nano-otp

# bun
bun add @ekaone/nano-otp

Usage

Generate an OTP

import { generate } from "@ekaone/nano-otp";

// default: 6-digit numeric OTP
const otp = generate();
console.log(otp);
// => "482910"

// custom length
const otp8 = generate({ length: 8 });
console.log(otp8);
// => "30571846"

// alpha charset (uppercase letters)
const otpAlpha = generate({ charset: "alpha" });
console.log(otpAlpha);
// => "KXRTBM"

// alphanumeric charset
const otpAlphaNum = generate({ charset: "alphanumeric", length: 8 });
console.log(otpAlphaNum);
// => "4BX9K2RZ"

// custom charset
const otpCustom = generate({ charset: "ABCDEF0123", length: 6 });
console.log(otpCustom);
// => "C3A0FB"

Verify an OTP

import { verify } from "@ekaone/nano-otp";

// basic match
const isValid = verify({ input: "482910", code: "482910" });
console.log(isValid);
// => true

// mismatch
const isInvalid = verify({ input: "000000", code: "482910" });
console.log(isInvalid);
// => false

// with expiry (expiresAt is a Unix timestamp in milliseconds)
const isValidWithExpiry = verify({
  input: "482910",
  code: "482910",
  expiresAt: Date.now() + 5 * 60 * 1000, // expires in 5 minutes
});
console.log(isValidWithExpiry);
// => true

// expired OTP
const isExpired = verify({
  input: "482910",
  code: "482910",
  expiresAt: Date.now() - 1000, // already expired
});
console.log(isExpired);
// => false

Generate a batch of OTPs

import { batch } from "@ekaone/nano-otp";

// generate 5 OTPs (may contain duplicates)
const otps = batch(5);
console.log(otps);
// => ["482910", "039471", "182930", "482910", "748201"]

// with options
const otpsAlpha = batch(3, { charset: "alpha", length: 8 });
console.log(otpsAlpha);
// => ["KXRTBMQZ", "LNVWACPD", "ERJHMKXB"]

Generate a batch of unique OTPs

import { batchUnique } from "@ekaone/nano-otp";

// generate 5 guaranteed-unique OTPs
const uniqueOtps = batchUnique(5);
console.log(uniqueOtps);
// => ["482910", "039471", "182930", "748201", "910284"]

Full workflow example

import { generate, verify } from "@ekaone/nano-otp";

// 1. generate and store OTP with a 10-minute expiry
const code = generate({ length: 6 });
const expiresAt = Date.now() + 10 * 60 * 1000;

console.log("Send this code to the user:", code);
// => "Send this code to the user: 482910"

// 2. later, verify what the user submitted
const userInput = "482910"; // submitted by user

const result = verify({ input: userInput, code, expiresAt });
console.log("Verification passed:", result);
// => "Verification passed: true"

API

generate(options?)

Generates a single cryptographically secure OTP.

generate(options?: OTPOptions): string
Option Type Default Description
length number 6 Length of the generated OTP
charset "numeric" | "alpha" | "alphanumeric" | string "numeric" Character set to use, or a custom string

verify(options)

Verifies an OTP using constant-time comparison to prevent timing attacks.

verify(options: VerifyOptions): boolean
Option Type Required Description
input string The OTP submitted by the user
code string The original generated OTP to compare against
expiresAt number Unix timestamp (ms) after which the OTP is invalid
now number Override current time (ms) — useful for testing

batch(count, options?)

Generates multiple OTPs. May contain duplicates.

batch(count: number, options?: OTPOptions): string[]
Parameter Type Description
count number Number of OTPs to generate
options OTPOptions Same options as generate

batchUnique(count, options?)

Generates multiple guaranteed-unique OTPs. Throws if the requested count exceeds the number of possible combinations for the given charset and length.

batchUnique(count: number, options?: OTPOptions): string[]
Parameter Type Description
count number Number of unique OTPs to generate
options OTPOptions Same options as generate

Types

interface OTPOptions {
  length?: number;
  charset?: "numeric" | "alpha" | "alphanumeric" | string;
}

interface VerifyOptions {
  input: string;
  code: string;
  expiresAt?: number;
  now?: number;
}

Security

  • Random generation uses Node.js crypto.randomInt — cryptographically secure, not Math.random()
  • verify uses constant-time comparison (XOR-based) to prevent timing attacks
  • Zero runtime dependencies — no supply chain risk from third-party packages

License

MIT © Eka Prasetia — see LICENSE for details.


Links

About

A tiny, zero-dependency One-Time Password (OTP) library for JavaScript and TypeScript.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors