Skip to main content

Node-keytar:把密码交还给操作系统钥匙串

· 5 min read

Node-keytar 是 Node.js 上最成熟的 OS 钥匙串绑定库 —— 但它 已经 archived

  1. 本质:原生模块,分别封装 macOS Keychain、Windows Credential Vault、Linux libsecret
  2. 核心 APIsetPassword / getPassword / deletePassword / findCredentials 四件套
  3. 适用场景:本地 CLI / 桌面工具保存用户 Token,不适合服务端容器
  4. 现状:仓库 2022-12 已 archived,最后版本 7.9.0 停更 4 年
  5. 替代方案:Electron 用 safeStorage,纯 Node 用 @napi-rs/keyring
  6. 跨平台:macOS / Win 零配置;Linux 需 libsecret-1-dev + Keyring 服务在跑

想存 API Token,怎么存

本地脚本要保存 GitHub / Notion 的 API Token,怎么存?

  • 写进 .env 文件 —— 等于明文裸奔
  • 自己 crypto 加解密 —— Key 放在哪都是问题
  • SQLite / 本地文件 + 混淆 —— 一样被反编译出来

真正的方案是 别自己存,把密码交给操作系统。macOS 钥匙串访问、Win 凭据管理器、Linux libsecret(GNOME Keyring / KWallet)都已经做好了 加密存盘 + 进程间隔离 + 用户登录解锁。Node-keytar 就是把它们封装成 Node.js 异步 API 的原生模块。

适用场景

适合用

  • 本地 CLI 工具保存用户登录态 —— 内网巡检脚本、GitLab/Jira/Notion 的 wrapper
  • VS Code、Postman 这类 IDE / 桌面应用的内部 keychain
  • ffmpeg、curl 等工具的 wrapper,要避免反复输入密码

不适合用

  • 服务端长跑进程 —— Docker 容器里没 Keyring 服务,K8s 里直接装不上
  • 跨机器迁移凭据 —— 钥匙串绑本机+当前用户,导不出去
  • 跑一次就丢的临时脚本 —— 用 readline-sync 问用户要更简单

基础使用

// npm 包名是 keytar;GitHub 仓库在 atom/node-keytar,这俩名字不一样
import keytar from 'keytar'

const SERVICE = 'com.example.my-cli' // 建议反向 DNS 命名

// 1. 存
await keytar.setPassword(SERVICE, 'user@example.com', 's3cret-token')

// 2. 取 —— 取不到返回 null,别当空串处理
const token = await keytar.getPassword(SERVICE, 'user@example.com')

// 3. 删 —— 返回 boolean,告诉你有没有删到东西
const removed = await keytar.deletePassword(SERVICE, 'user@example.com')

// 4. 列(同 service 下所有账号)
const all = await keytar.findCredentials(SERVICE)
// → [{ account: 'a@b.com', password: 'xxx' }, ...]
速查要点

4 个 API 就够覆盖 90% 场景。剩下的两个是次要工具:findPassword(只查第一个匹配,等价于 findCredentials[0]?.password)、getServiceName(OS 默认服务名,基本不用),按需查就行。

安装 + 跨平台坑

pnpm add keytar # npm 包名是 keytar,不是 node-keytar

keytar 是 N-API 原生模块pnpm add keytar 不只是下个 JS 文件,背后跑了 6 步:

  1. 拉 tarball(含 C++ 源码 + JS 胶水 + binding.gyp
  2. node-gyp(编译工具链)
  3. 探测本机 ABI(Node 版本 + 平台,如 darwin-arm64
  4. 去 CDN 拉匹配 ABI 的预编译 .node 二进制
  5. 没预编译就 node-gyp rebuild 从 C++ 现编(要 Python + C++ 工具链)
  6. JS 胶水 require('./build/Release/keytar.node') 加载 native binding

第 4 步成功 = 几秒装完;第 4 步失败 + 第 5 步缺工具链 = 整个 install 卡死 —— 这就是 Node 20/22 上"装不上"的本质。

平台体验
macOS✅ 预编译 .node 直接加载,零配置
Windows✅ 同上
Linux⚠️ 装包时需要 libsecret-1-dev(Debian/Ubuntu),运行时必须有 Keyring 服务在跑

Node 20/22 用户的踩坑点7.9.0 预编译只覆盖到 Node 17 的 N-API ABI。装到 Node 20/22 时第 4 步找不到预编译,回退到第 5 步需要 Python 3 + C++ 工具链(Windows 还要 VS Build Tools),公司机器没装的话直接 No prebuilt binaries found(参考 issue #317)。

这个坑也是 2022 年仓库归档的直接原因之一 —— 维护成本 cover 不住 N-API ABI 的快速演进。

现状:用还是不用

atom/node-keytar2022-12-15 被 GitHub 归档,最后一个发版 7.9.0 至今没动过。但 npm 周下载量依然有 ~100 万 —— 是 VS Code、Electron、Yeoman 等老牌项目的依赖在拖它。

你的场景推荐选择
Electron 桌面应用electron.safeStorage(内置,OS Keychain 加密,VS Code 已迁移)
纯 Node.js / CLI 工具@napi-rs/keyring(Rust + N-API,主动维护,新版 Node 预编译齐)
已经在用 keytar能跑不动就别动,别在新项目里引

社区 fork(dreamboysv3/node-keytar 等)只是同 API 改名,没解决 Node 版本问题。迁移成本最低的是 @napi-rs/keyring —— API 几乎一致,type 重命名一下就行。

说白了,Node-keytar 是 Node.js 历史上一座重要的桥梁 —— 在 libsecret / safeStorage 成熟之前,它让 CLI 工具获得了"正经"的凭据存储能力。但 2026 年的新项目,应该让它功成身退了。

References

  1. atom/node-keytar —— 已 archived(2022-12-15),最后发版 7.9.0(2022-02)
  2. @napi-rs/keyring —— Rust 实现的活跃替代品,API 接近
  3. Electron safeStorage API —— Electron 桌面端推荐方案