jose、jsonwebtoken、jwa、jws、node-jose は、すべて JSON Web Token (JWT) や関連する暗号規格(JWS, JWE, JWK)を扱うための Node.js ライブラリですが、その役割と設計思想は大きく異なります。
jsonwebtoken は長年デファクトスタンダードとして使われてきた高レベルなライブラリで、JWT の署名と検証を単純な API で提供します。一方、jose はモダンな設計で、ブラウザと Node.js の両方で動作し、JWT だけでなく JWE(暗号化)や JWK(鍵管理)も包括的にサポートする次世代の標準です。
jws と jwa は、より低レベルな処理に特化しています。jws は JWT の署名部分のみを扱い、jwa はアルゴリズムの識別子変換など基礎的な utilities を提供します。これらは通常、独自の実装が必要な場合に使用されます。
node-jose はかつて JWE サポートで重要でしたが、現在はメンテナンスが停滞しており、新しいプロジェクトでの使用は推奨されません。現代の開発では、セキュリティと将来性を考慮し jose への移行が強く推奨されています。
Node.js で認証システムを構築する際、JSON Web Token (JWT) の扱いは避けて通れません。しかし、npm には類似した名前のパッケージが乱立しており、どれを選べばよいのか迷う開発者は少なくありません。
ここでは、jose、jsonwebtoken、jws、jwa、node-jose の 5 つを徹底比較します。単なる機能リストではなく、実際のコードがどう変わるか、セキュリティ面で何が違うかに焦点を当てて解説します。
まず理解すべきは、これらのライブラリが「どのレベル」の抽象化を提供しているかです。
jsonwebtoken と jose は「高レベル」ライブラリです。これらは、署名の生成、トークンの検証、有効期限のチェックまでをワンステップで処理します。
一方、jws と jwa は「低レベル」な部品です。jws は署名の作成のみを行い、有効期限のチェックなどは行いません。jwa に至っては、アルゴリズム名の文字列操作などが主な役割です。
node-jose はかつて高レベルな選択肢でしたが、現在は時代遅れとなっています。
最も一般的なユースケースである「トークンの発行」と「検証」を、主要な 2 つの高レベルライブラリで比較します。
jsonwebtoken の実装長年使われてきたこのライブラリは、API が非常にシンプルです。秘密鍵を渡すだけで署名付きトークンが生成できます。
const jwt = require('jsonwebtoken');
const secret = 'my-secret-key';
// 署名 (Sign)
const token = jwt.sign(
{ userId: 123, role: 'admin' },
secret,
{ expiresIn: '1h' }
);
// 検証 (Verify)
try {
const decoded = jwt.verify(token, secret);
console.log(decoded.userId); // 123
} catch (err) {
console.error('Invalid token');
}
jose の実装jose はより明示的で、モダンな Promise ベースの API を採用しています。鍵の扱いも厳格で、セキュリティ上のミスが減りやすい設計です。
import { SignJWT, jwtVerify } from 'jose';
import { textEncoder } from 'jose/util';
const secret = new TextEncoder().encode('my-secret-key');
// 署名 (Sign)
const token = await new SignJWT({ userId: 123, role: 'admin' })
.setProtectedHeader({ alg: 'HS256' })
.setExpirationTime('1h')
.sign(secret);
// 検証 (Verify)
try {
const { payload } = await jwtVerify(token, secret);
console.log(payload.userId); // 123
} catch (err) {
console.error('Invalid token');
}
比較のポイント: jsonwebtoken は同期処理のように見えますが、内部で暗号化処理を行っています。jose は非同期処理であることを明確にし、アルゴリズムをヘッダーで明示的に指定させることで、アルゴリズム混在攻撃(Algorithm Confusion Attack)を防ぐ設計になっています。
なぜ jws や jwa といったライブラリが存在するのでしょうか?それは、JWT の仕組みを完全にコントロールしたい場合や、独自のプロトコルを構築する必要がある場合です。
jws の実装jws は、JWT の「署名部分」のみを作成・検証します。ペイロードの中身や有効期限(exp)のチェックは行いません。
const jws = require('jws');
// 署名の作成
const signature = jws.sign({
header: { alg: 'HS256' },
payload: { userId: 123 },
secret: 'my-secret-key'
});
// 署名の検証(中身のチェックはしない)
const isValid = jws.verify(signature, 'HS256', 'my-secret-key');
if (isValid) {
const decoded = jws.decode(signature); // ペイロードを取り出すだけ
console.log(decoded.payload);
}
このように、jws を使うと「有効期限が切れていても署名が合っていれば true を返す」ため、認証ロジックを自分で全て書く必要があります。通常のプロダクションコードでは、このライブラリを直接使用することは稀です。
jwa の実装jwa は、アルゴリズム名の正規化など、極めて基礎的な処理を行います。例えば、RS256 と rsa-sha2-256 のような表記ゆれを吸収する際などに使われます。
const jwa = require('jwa');
// アルゴリズムエイリアスの解決
const algo = jwa('RS256');
console.log(algo.algorithm); // 'RS256'
// 通常、開発者が直接呼び出す機会はほとんどありません
// 他のライブラリ内部で使用されることが多いです
JWT には、署名だけでなく「暗号化」されたタイプ(JWE)があります。機密情報をトークン自体に含めたい場合に必要です。
node-jose の現状と限界かつて node-jose は、Node.js で JWE を扱うための数少ない選択肢でした。
// 【非推奨】node-jose の例
const jose = require('node-jose');
// 鍵の準備と暗号化
jose.JWK.createKeyStore().then((keystore) => {
return keystore.generate('oct', 256).then((key) => {
return jose.JWE.createEncrypt({ format: 'compact' }, key)
.update(JSON.stringify({ data: 'secret' }))
.final();
});
});
しかし、このライブラリは更新が止まっており、セキュリティのパッチも適用されていません。新しいプロジェクトで node-jose を選ぶべきではありません。
jose による JWE 実装現代の正解は jose です。JWE の作成も JWT と同様にモダンな API で処理できます。
import { CompactEncrypt } from 'jose';
import { generateSecret } from 'jose/util';
// 対称鍵の生成
const secret = await generateSecret('A256GCM');
// 暗号化 (Encrypt)
const encryptedToken = await new CompactEncrypt(
new TextEncoder().encode(JSON.stringify({ data: 'secret' }))
)
.setProtectedHeader({ alg: 'dir', enc: 'A256GCM' })
.encrypt(secret);
console.log(encryptedToken);
// 結果は JWE 形式の文字列になります
jose は JWE だけでなく、JWK(JSON Web Key)のインポート・エクスポートも容易に扱えるため、鍵管理システムとの連携もスムーズです。
アーキテクチャを決定する際、どこでコードを動かすかは重要です。
| ライブラリ | Node.js | ブラウザ | 備考 |
|---|---|---|---|
jose | ✅ | ✅ | 単一コードベースで両方対応可能 |
jsonwebtoken | ✅ | ❌ | Node.js の crypto モジュールに依存 |
jws | ✅ | ⚠️ | ブラウザではポリフィルが必要 |
jwa | ✅ | ⚠️ | 同上 |
node-jose | ✅ | ❌ | 非推奨 |
jsonwebtoken は Node.js 固有の機能を使っているため、ブラウザ(React や Vue のフロントエンドコード内など)で動かすことはできません。一方、jose は Web Crypto API を活用しているため、サーバーとクライアントで同じライブラリを共有できます。
選択を誤ると、セキュリティリスクに直結します。
node-jose: メンテナンス終了。既知の脆弱性が放置されている可能性があります。即刻移行を検討してください。jsonwebtoken: 広く使われていますが、機能追加はほぼ停止しており、バグフィックス中心のメンテナンスモードです。アルゴリズムの指定を怠るとセキュリティホールになる過去の実装方針でした。jose: 現在最もアクティブに開発されており、最新の仕様を追従しています。デフォルトで安全な設定が多く、誤用を防ぐ設計になっています。実際のプロジェクトでは、以下のように判断するのが賢明です。
→ jose 一択です。
ブラウザとサーバーでコードを共有でき、JWE への拡張も容易です。将来のセキュリティ要件の変化にも柔軟に対応できます。
→ jsonwebtoken のまま維持するか、段階的に jose へ移行。
すぐに書き換える必要はありませんが、新規機能追加時には jose を導入し、徐々に置き換えるのが現実的です。
→ jws を検討。
標準的な JWT のルールに縛られず、ヘッダーやペイロードの構造を完全にカスタマイズする場合のみ使用します。
| 機能 | jose | jsonwebtoken | jws | node-jose |
|---|---|---|---|---|
| JWT 署名・検証 | ✅ | ✅ | ⚠️ (署名のみ) | ✅ |
| JWE (暗号化) | ✅ | ❌ | ❌ | ✅ |
| ブラウザ対応 | ✅ | ❌ | ⚠️ | ❌ |
| Promise 対応 | ✅ (Native) | ❌ (Callback/Promise) | ❌ | ✅ |
| メンテナンス | 🟢 活発 | 🟡 保守のみ | 🟡 保守のみ | 🔴 終了 |
| 推奨度 | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐ | ❌ |
迷ったら jose を使ってください。それは単に「新しいから」ではなく、セキュリティ設計が現代的であり、ブラウザ環境も含めた幅広いユースケースをカバーしているからです。
jsonwebtoken は過去の資産として尊重しつつ、node-jose は過去のものとしてアーカイブに送る。これが、2024 年以降の Node.js エコシステムにおける正しい立ち位置です。低レベルな jws や jwa は、本当に必要な時が来るまで、その存在を頭の片隅に置いておくだけで十分でしょう。
新しいプロジェクトでは常に jose を選定すべきです。このライブラリは Node.js とブラウザの両方で動作し、JWT だけでなく JWE(暗号化)や JWK の操作もサポートしています。依存関係が少なく、モダンな Promise ベースの API を提供するため、セキュリティ要件が高く将来の拡張性を考慮する場合に最適です。
既存のレガシーコードベースを維持する場合や、極めて単純な JWT 署名・検証のみが必要な場合は jsonwebtoken が適しています。ただし、JWE への対応がなく、メンテナンスモードに入っているため、新規プロジェクトでの採用は避けるべきです。
JWT の完全な実装ではなく、アルゴリズム名の正規化や署名アルゴリズムの識別など、極めて基礎的な処理のみを必要とする場合に使用します。通常、エンドユーザーが直接利用するライブラリではなく、他のツールを開発する際の部品として使われます。
JWT のヘッダーと署名部分のみを分離して扱いたい場合、あるいはペイロードの検証ロジックを完全に自作する場合に使用します。標準的な JWT 認証を実装するだけなら、より高レベルな jose や jsonwebtoken を使うべきであり、このライブラリは特殊なユースケースに限られます。
このライブラリは現在事実上メンテナンスが終了しており、新しいプロジェクトで使用してはいけません。過去に JWE 機能が必要で jose が未成熟だった時期に選ばれましたが、現在は jose がその役割を完全に代替しています。既存システムからの移行を検討してください。
jose is a JavaScript module for JSON Object Signing and Encryption, providing support for JSON Web Tokens (JWT), JSON Web Signature (JWS), JSON Web Encryption (JWE), JSON Web Key (JWK), JSON Web Key Set (JWKS), and more. The module is designed to work across various Web-interoperable runtimes including Node.js, browsers, Cloudflare Workers, Deno, Bun, and others.
If you want to quickly add JWT authentication to JavaScript apps, feel free to check out Auth0's JavaScript SDK and free plan. Create an Auth0 account; it's free!
Support from the community to continue maintaining and improving this module is welcome. If you find the module useful, please consider supporting the project by becoming a sponsor.
jose has no dependencies and it exports tree-shakeable ESM1.
jose is distributed via npmjs.com, jsr.io, jsdelivr.com, and github.com.
example ESM import1
import * as jose from 'jose'
The jose module supports JSON Web Tokens (JWT) and provides functionality for signing and verifying tokens, as well as their JWT Claims Set validation.
jwtVerify function
SignJWT classThe jose module supports encrypted JSON Web Tokens and provides functionality for encrypting and decrypting tokens, as well as their JWT Claims Set validation.
jwtDecrypt functionEncryptJWT classThe jose module supports importing, exporting, and generating keys and secrets in various formats, including PEM formats like SPKI, X.509 certificate, and PKCS #8, as well as JSON Web Key (JWK).
The jose module supports signing and verification of JWS messages with arbitrary payloads in Compact, Flattened JSON, and General JSON serialization syntaxes.
The jose module supports encryption and decryption of JWE messages with arbitrary plaintext in Compact, Flattened JSON, and General JSON serialization syntaxes.
The following are additional features and utilities provided by the jose module:
The jose module is compatible with JavaScript runtimes that support the utilized Web API globals and standard built-in objects or are Node.js.
The following runtimes are supported (this is not an exhaustive list):
Please note that certain algorithms may not be available depending on the runtime used. You can find a list of available algorithms for each runtime in the specific issue links provided above.
| Version | Security Fixes 🔑 | Other Bug Fixes 🐞 | New Features ⭐ | Runtime and Module type |
|---|---|---|---|---|
| v6.x | Security Policy | ✅ | ✅ | Universal2 ESM1 |
The algorithm implementations in jose have been tested using test vectors from their respective specifications as well as RFC7520.