Node-keytar:把密码交还给操作系统钥匙串
Node-keytar 是 Node.js 上最成熟的 OS 钥匙串绑定库 —— 但它 已经 archived。
- 本质:原生模块,分别封装 macOS Keychain、Windows Credential Vault、Linux libsecret
- 核心 API:
setPassword/getPassword/deletePassword/findCredentials四件套 - 适用场景:本地 CLI / 桌面工具保存用户 Token,不适合服务端容器
- 现状:仓库 2022-12 已 archived,最后版本
7.9.0停更 4 年 - 替代方案:Electron 用
safeStorage,纯 Node 用@napi-rs/keyring - 跨平台: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 步:
- 拉 tarball(含 C++ 源码 + JS 胶水 +
binding.gyp) - 装
node-gyp( 编译工具链) - 探测本机 ABI(Node 版本 + 平台,如
darwin-arm64) - 去 CDN 拉匹配 ABI 的预编译
.node二进制 - 没预编译就
node-gyp rebuild从 C++ 现编(要 Python + C++ 工具链) - 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-keytar 在 2022-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
- atom/node-keytar —— 已 archived(2022-12-15),最后发版 7.9.0(2022-02)
- @napi-rs/keyring —— Rust 实现的活跃替代品,API 接近
- Electron safeStorage API —— Electron 桌面端推荐方案