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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@db-node/jwt

v0.1.1

Published

Tiny, type-safe JWT toolkit on top of jsonwebtoken — sign / verify / decode / expiry check, with factory & functional APIs.

Readme

@db-node/jwt

Tiny, type-safe JWT toolkit on top of jsonwebtoken — sign / verify / decode / expiry check, with both functional and factory APIs.

  • ✅ TypeScript 优先,完整泛型推断
  • ✅ 同时提供函数式 API实例化工厂 createJwt
  • ✅ 安全默认:禁用 'none' 算法、verify 时强制 algorithm 白名单
  • ✅ 提供"不抛错"的 verifySafe,错误结构化分类
  • ✅ 不验签的 decode / isExpired / getRemainingTtl 工具函数
  • extractBearer 一行解析 Authorization header

Install

pnpm add @db-node/jwt
# or: npm i @db-node/jwt

Quick Start

函数式 API(一次性调用 / 简单场景)

import { sign, verify, isExpired } from '@db-node/jwt';

const token = sign({ userId: 1, role: 'admin' }, 'my-secret', {
  expiresIn: '1h',
});

const payload = verify<{ userId: number; role: string }>(token, 'my-secret');
// payload.userId === 1

if (isExpired(token)) {
  // 主动刷新
}

实例化 API(业务推荐)

import { createJwt } from '@db-node/jwt';

const jwt = createJwt({
  secret: process.env.JWT_SECRET!,
  expiresIn: '1h',
  issuer: 'my-app',
});

const token = jwt.sign({ userId: 1 });
const payload = jwt.verify(token);          // 失败抛错
const safe   = jwt.verifySafe(token);       // 不抛错,结构化结果

API

sign(payload, secret, options?) → string

签发一个 JWT token。

| 参数 | 类型 | 说明 | | --------- | ------------------------------------ | --------------------------------------------------- | | payload | T extends Record<string, any> | 业务载荷 | | secret | string \| Buffer \| KeyObject | HS* 用共享密钥;RS* / ES* / PS* 用私钥 | | options | SignOpts | 可选;如 expiresIn / algorithm / issuer 等 |

const token = sign(
  { userId: 1 },
  fs.readFileSync('private.pem'),
  { algorithm: 'RS256', expiresIn: '7d', issuer: 'my-app' },
);

verify(token, secret, options?) → T

验证签名 + 标准 claim(exp/nbf/iss/aud/sub),失败抛错

可能抛出:

  • TokenExpiredError — token 已过期
  • NotBeforeError — 未到 nbf 生效时间
  • JsonWebTokenError — 签名错误 / 算法不匹配 / token 格式非法
try {
  const payload = verify<{ userId: number }>(token, secret);
} catch (e: any) {
  if (e.name === 'TokenExpiredError') /* ... */;
}

verifySafe(token, secret, options?) → VerifyResult<T>

verify 行为一致,但永不抛错,返回结构化结果。

type VerifyResult<T> =
  | { ok: true;  payload: T }
  | { ok: false; error: { kind: VerifyErrorKind; message: string; cause?: unknown } };

type VerifyErrorKind =
  | 'TokenExpiredError'
  | 'NotBeforeError'
  | 'JsonWebTokenError'
  | 'UnknownError';
const r = verifySafe<{ uid: number }>(token, secret);
if (!r.ok) {
  switch (r.error.kind) {
    case 'TokenExpiredError': ctx.throw(401, 'expired'); break;
    case 'NotBeforeError':    ctx.throw(401, 'not active'); break;
    default:                  ctx.throw(401, 'invalid token');
  }
}

decode<T>(token) → T | null

仅 base64url 解码 payload,不验证签名。token 格式非法返回 null

const p = decode<{ exp: number }>(token);
console.log(p?.exp);

decodeComplete<T>(token) → { header, payload, signature } | null

完整解码,可读 header 中的 kid / alg 等。

const full = decodeComplete(token);
const kid = full?.header.kid;

isExpired(token, leewaySec?) → boolean | null

仅根据 payload.exp 判断是否过期,不验证签名

| 返回值 | 含义 | | ------- | ----------------------------------- | | true | 已过期 | | false | 未过期 | | null | 无 exp 字段 / token 格式非法 |

if (isExpired(token, 30) === true) refresh();   // 容忍 30s 漂移

getRemainingTtl(token) → number | null

返回 token 剩余有效秒数(已过期返回 0,无 exp 返回 null)。

const ttl = getRemainingTtl(token);
if (ttl !== null && ttl < 300) refresh();        // 5min 内过期则刷新

extractBearer(header) → string | null

Authorization header 中提取 token,兼容大小写与多余空格。

const token = extractBearer(req.headers.authorization);
//             ^ "Bearer xxx.yyy.zzz" → "xxx.yyy.zzz"

createJwt(options) → JwtInstance

创建一个 JWT 实例,复用默认配置。所有方法的最后一个参数 overrides 都可临时覆盖默认值。

const jwt = createJwt({
  secret: 'my-secret',         // HS* 必填;非对称时这里放私钥
  publicKey: undefined,        // 非对称时这里放公钥(HS* 留空)
  algorithm: 'HS256',          // 默认 HS256
  expiresIn: '1h',
  issuer: 'my-app',
  audience: 'web',
  subject: undefined,
  clockTolerance: 5,           // 容忍 5s 时钟漂移
});

jwt.sign({ userId: 1 });                       // 用默认配置签发
jwt.sign({ userId: 1 }, { expiresIn: '7d' }); // 临时改 7d
jwt.verify(token);
jwt.verifySafe(token);
jwt.isExpired(token);
jwt.getRemainingTtl(token);
jwt.decode(token);
jwt.decodeComplete(token);
jwt.extractBearer(authHeader);
jwt.options;                                    // 只读快照

非对称算法(RS256 示例)

import fs from 'node:fs';
import { createJwt } from '@db-node/jwt';

const jwt = createJwt({
  algorithm: 'RS256',
  secret:    fs.readFileSync('private.pem'),   // 签发用私钥
  publicKey: fs.readFileSync('public.pem'),    // 验证用公钥
  expiresIn: '7d',
  issuer:    'my-app',
});

自定义每次签发的 key

若不同请求需要不同密钥,建议使用函数式 API:

import { sign, verify } from '@db-node/jwt';

const token = sign({ x: 1 }, lookupSecretByTenant(tenantId), { expiresIn: '1h' });
const data  = verify(token, lookupSecretByTenant(tenantId));

Types

SignOpts

jsonwebtoken 原生 SignOptions 的子集(algorithm 收紧到白名单)。常用:

  • expiresIn: '1h' | '7d' | number
  • notBefore: string | number
  • algorithm: JwtAlgorithm
  • issuer / audience / subject / jwtid
  • header(自定义 JOSE header)
  • keyid(→ header.kid)

VerifyOpts

jsonwebtoken 原生 VerifyOptionsalgorithms 收紧到白名单)。常用:

  • algorithms: JwtAlgorithm[](防降级)
  • issuer / audience / subject
  • clockTolerance: number
  • maxAge: string | number
  • ignoreExpiration: boolean

JwtAlgorithm

HS256 | HS384 | HS512
RS256 | RS384 | RS512
ES256 | ES384 | ES512
PS256 | PS384 | PS512

⚠️ 'none' 已被禁用(防降级攻击)。


Legacy API(旧项目无痛迁移)

如果你的旧项目长这样:

// jwt.js(旧)
const jwt = require('jsonwebtoken');
const { privatekey } = require('../comm/constant');

const generateToken = (userName) => jwt.sign({ username: userName }, privatekey, { expiresIn: '30d' });
const validToken = (token) => { /* ... */ };
const tokenUserName = (token) => { /* ... */ };
const tokenUserNamePromise = (token) => { /* ... */ };
const decryptToken = (token) => { /* ... */ };

module.exports = { jwt, privatekey, generateToken, decryptToken, validToken, tokenUserName, tokenUserNamePromise };

只需替换为:

// jwt.js(新)
const { createLegacyAuth } = require('@db-node/jwt');
const { privatekey } = require('../comm/constant');

module.exports = createLegacyAuth(privatekey);
// 可选:自定义过期时间
// module.exports = createLegacyAuth(privatekey, { expiresIn: '7d' });

业务侧 require('./jwt') 解构出来的 7 个字段一字不差。

Legacy 函数清单

| 字段 | 类型 | 说明 | | -------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------- | | jwt | typeof jsonwebtoken | 透传 jsonwebtoken | | privatekey | JwtSecret | 初始化时传入的密钥回显 | | generateToken(userName) | (userName) => string | 签发 token,payload = { username: userName },默认 30 天 | | decryptToken(token) | (token) => object \| null | 不验签解码(修复了旧版 bug:旧版会把 token 当 username 再签发再解码) | | validToken(token) | (token) => { err_code, data, message } | 合法 {200, true, '成功'} / 非法 {100, false, 'token过期或无效'} | | tokenUserName(token) | 成功返回 payload / 失败返回 err_code 对象 | 注意返回结构异质(保留旧契约,建议新代码改用 verifySafe) | | tokenUserNamePromise(token) | (token) => Promise<payload \| err_code> | Promise 版,永不 reject(修复了旧版 try/catch 不生效的问题) |

⚠️ 与原实现的两处语义修复

  1. decryptToken 现在真的解码传入的 token(旧版是 decode(generateToken(token)),是 bug)
  2. tokenUserNamePromise 失败时 resolve 错误对象(旧版外层 try/catch 实际不会触发,verify 同步抛错会被 Promise 构造函数捕获并 reject,外部 await 会拿到拒绝)

安全建议

  1. 密钥:HS* 建议 ≥ 32 字节;RS* / ES* 使用标准 PEM。
  2. algorithms 白名单:实例化 API 默认强制约束,无需额外配置。
  3. exp 必须设置:所有 token 都建议指定 expiresIn,避免长期有效。
  4. 不要用 decode 做鉴权:它不验签,仅适合读取元信息。
  5. issuer / audience 校验:多服务共享时务必配置,防止 token 跨域被复用。

License

MIT