@chax-at/totp

中文文档
1.0.0发布于 2025/06/17MITTypeScriptCommonJS零依赖构建来源已验证近 30 天下载 3639

A simple TOTP package

原始使用文档
文档目录5 节
  1. Usage
  2. TotpManager
  3. Creating a secret
  4. Verifying a TOTP code
  5. Why yet another TOTP package?

@chax-at/totp

A simple package which can be used to implement TOTP two-factor codes. Implements the default use case (6-digit codes, 30s time steps, 20-byte/160-bit base32-encoded secret, using SHA1) but doesn't provide much customization.

These default values are the most common and should be supported in all authenticator apps. If you're wondering why you may want to use this package instead of others, check the section Why yet another TOTP package at the bottom.

Usage

Install the package by running

npm i @chax-at/totp

TotpManager

Then, you can create a TotpManager to generate secrets and verify codes. You can create a TotpManager like this:

import { TotpManager } from '@chax-at/totp';

const totpManager = new TotpManager({
  // This issuer will be shown in the user's authenticator app and should be something like your company/service name
  issuer: 'ExampleWebsite',
  // You can also specify `verifyWindow` here. Defaults to 2 which means that the TOTP code at current time is valid as well as the previous 2 and next 2
});

Creating a secret

Assuming user [email protected] wants to enable two factor using their TOTP app. You now can generate a secret for this user:

// Include the user's account name/email here which is shown in their authenticator app when scanning the QR code
const { secret, otpauthUri } = totpManager.generateSecret('[email protected]');
  • Save the returned secret for the user in your database. It is recommended to encrypt this secret (note that you can't hash it because you need it in plaintext to verify codes).

We also RECOMMEND storing the keys securely in the validation system, and, more specifically, encrypting them using tamper-resistant hardware encryption and exposing them only when required: for example, the key is decrypted when needed to verify an OTP value, and re-encrypted immediately to limit exposure in the RAM to a short period of time. RFC 6238, 5.1

  • Generate a QR code containing the returned otpauthUri and show it to your user. They can then scan it with their authenticator app.
  • You may also show the secret so they can manually register your application in case the QR code doesn't work.
  • You should require a user to enter one valid code before actually enabling two-factor authentication.

Verifying a TOTP code

Assuming the user entered the code 123456, then you can verify it like this:

// Returns whether the code is valid at the current time. Also returns true if it matches the previous/next [verifyWindow] codes as defined above
const isValid = totpManager.verify(secret, '123456');
  • You should rate limit the TOTP verification so that attackers can't brute-force TOTP codes (there are only 1 000 000 possible codes)
  • You should save (and deny) "used" correct tokens per user for at least 30s + 30s * verifyWindow [default 2] so that your one-time password (the "OTP" part of TOTP) can actually only be used one time

Note that a prover may send the same OTP inside a given time-step window multiple times to a verifier. The verifier MUST NOT accept the second attempt of the OTP after the successful validation has been issued for the first OTP, which ensures one-time only use of an OTP. RFC 6238, 5.2

Why yet another TOTP package?

There are some widely used node TOTP/2FA packages available. However, when I researched them, all of them seemed to be unmaintained and have some areas that could be improved (including security-critical issues).

Your use-case might vary (e.g. if you need more customization than this package can offer), but here are the reasons why I didn't use other packages and decided to write my own:

  • speakeasy seems to be the most recommended package in tutorials. However, it doesn't generate secure secrets.
    • speakeasy forgot that the letter "j" exists, therefore it doesn't appear in the secret at all [source]
    • speakeasy introduces a bias in the secret which prevents it from being completey random, making attacks easier. There is a PR attempting to fix it - but the package is not maintained.
  • otplib has even more weekly downloads and doesn't have a bias in their secret generation. However, their generated secrets are way too short (unless you specify a length) and don't even meet the minimum defined in the TOTP specification.
    • RFC 4226 states that "The length of the shared secret MUST be at least 128 bits. This document RECOMMENDs a shared secret length of 160 bits."
    • This means that a secret must be at least 16 bytes long, and is recommended to be 20 bytes long (which this @chax-at/totp uses)
    • However, otplib changed their default (in a 20k lines changed commit) in 12.0.0 from a secure 20 bytes to just 10 bytes (80 bits) [source]
      • This was not mentioned in the upgrade guide
      • The issue mentioning this from 2022 has no response from the maintainer
    • I can't say much about the rest of the library because the code is split up in 12 packages (compared to the 2 files with 40/70 lines each in @chax-at/totp) and I couldn't track all those abstraction layers by clicking through files in GitHub
  • node-2fa doesn't have obvious security issues. However, there are still some things stopping me from using it.
    • generateSecret also returns a helpful QR code link - that immediately sends your secret to Google. You should really generate your own QR codes instead of sending your secrets to Google.
    • It depends on notp for key generation
      • notp contains code that has been deprecated in node, e.g. new Buffer(...). This is not a security issue - but will show a deprecation warning for everyone using their package. There is a PR from 2021 which has not been merged yet.
    • This package doesn't have a changelog (or at least I couldn't find it)
  • No other package uses constant-time comparisons for checking the code. I don't think that timing attacks are very likely, but using a constant-time comparison function prevents these attacks.

版本与发布记录

@chax-at/totp 共发布 5 个版本,首次发布于 2024/03/01;过去 12 个月发布了 0 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.0.0latest2025/06/171.4 年前
0.2.12024/03/082 年前
0.2.02024/03/082 年前
0.1.12024/03/032 年前
0.1.02024/03/012 年前

关于 @chax-at/totp 的常见问题

@chax-at/totp 是什么?

A simple TOTP package

如何安装 @chax-at/totp?

在项目目录运行 npm install @chax-at/totp,或使用 pnpm add / yarn add / bun add。

@chax-at/totp 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@chax-at/totp 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@chax-at/totp 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >= 20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@chax-at/totp 可以商用吗?

@chax-at/totp 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@chax-at/totp 的下载量有多少?

根据 npm 官方下载统计,@chax-at/totp 在 2026/10/10 – 2026/11/08 这 30 天内被下载 3,639 次,日均约 121 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@chax-at/totp 还在维护吗?

最新版本 1.0.0 发布于 2025/06/17(1.4 年前);至今共发布 5 个版本,其中过去 12 个月发布了 0 个;首次发布于 2024/03/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。