Node.js JWT 検証例
⚠️ 重要なお知らせ: これはデモンストレーション目的の基本的な例です。実運用で使用する 際は、ソフトウェアスタック、セキュリティ要件、デプロイ環境に特化したベストプラクティスを調査し、実装してください。常に組織のセキュリティガイドラインに従い、確立されたJWTライブラリやフレームワークの使用を検討してください。
📝 注記: この例は教育目的でJWKSのダウンロードとファイルキャッシングを示しています。実運用環境では、インフラストラクチャに基づいて異なるJWKSキー管理を実装することを選択するかもしれません。たとえば、構成管理、環境変数、またはお好みのキャッシング戦略を使用するなどです。
この例は、Node.jsを使用してRokt JWTトークンを検証する方法を示しています。
前提条件
必要なパッケージをインストールします:
npm install jose jsonwebtoken
完全な例
const { jwtVerify, importJWK } = require('jose');
const jwt = require('jsonwebtoken');
// RoktからのサンプルJWTト ークン
// 概要ページからテストトークンをコピー
const SAMPLE_JWT_TOKEN = "PASTE_TEST_TOKEN_HERE";
// JWKSエンドポイントURL
const JWKS_URL = "https://public-api.rokt.com/.well-known/jwks.json";
const JWKS_CACHE_FILE = "jwks_cache.json";
/**
* joseライブラリを使用してJWTトークンを検証する(推奨)
*/
async function validateReferralTokenJose(jwtToken, jwksJson) {
try {
// JWKSを解析
const jwks = typeof jwksJson === 'string' ? JSON.parse(jwksJson) : jwksJson;
if (!jwks.keys || jwks.keys.length === 0) {
throw new Error('JWKSにキーが見つかりません');
}
// 最初のキーを取得
const jwk = jwks.keys[0];
// 公開鍵を作成するためにJWKをインポート
const publicKey = await importJWK(jwk, 'ES256');
// JWTトークンを検証およびデコード
const { payload } = await jwtVerify(jwtToken, publicKey, {
algorithms: ['ES256'],
clockTolerance: '1m' // 1分の時計のずれを許可
});
return {
isValid: true,
campaignID: payload.cid,
creativeID: payload.crid,
rclid: payload.rclid,
issuedAt: new Date(payload.iat * 1000)
};
} catch (error) {
return {
isValid: false,
error: error.message
};
}
}
/**
* jsonwebtokenライブラリを使用した代替実装
*/
function validateReferralTokenJWT(jwtToken, jwksJson) {
try {
// JWKSを解析
const jwks = typeof jwksJson === 'string' ? JSON.parse(jwksJson) : jwksJson;
if (!jwks.keys || jwks.keys.length === 0) {
throw new Error('JWKSにキーが見つかりません');
}
// 最初のキーを取得
const jwk = jwks.keys[0];
// jsonwebtokenの場合、JWKをPEM形式に変換する必要があります
// これは簡略化された例です - 実際には、適切なJWKからPEMへの変換が必要です
const publicKeyPem = `-----BEGIN PUBLIC KEY-----
YOUR_PUBLIC_KEY_PEM_HERE
-----END PUBLIC KEY-----`;
// JWTトークンを検証およびデコード
const decoded = jwt.verify(jwtToken, publicKeyPem, {
algorithms: ['ES256'],
clockTolerance: 60 // 1分の時計のずれを許可
});
return {
isValid: true,
campaignID: decoded.cid,
creativeID: decoded.crid,
rclid: decoded.rclid,
issuedAt: new Date(decoded.iat * 1000)
};
} catch (error) {
return {
isValid: false,
error: error.message
};
}
}
/**
* トークンの検証をデモンストレーションするメイン関数
*/
async function downloadAndCacheJWKS(jwksUrl, cacheFile) {
const fs = require('fs');
const path = require('path');
// キャッシュファイルが存在し、最近のものであるか(24時間未満)を確認
if (fs.existsSync(cacheFile)) {
const stats = fs.statSync(cacheFile);
const fileAge = Date.now() - stats.mtime.getTime();
if (fileAge < 86400000) { // 24時間をミリ秒で
console.log(`キャッシュされたJWKSを使用: ${cacheFile}`);
return fs.readFileSync(cacheFile, 'utf8');
}
}
// JWKSをダウンロード
console.log(`JWKSをダウンロード中: ${jwksUrl}`);
const response = await fetch(jwksUrl);
if (!response.ok) {
throw new Error(`JWKSのダウンロードに失敗しました: HTTP ${response.status}`);
}
const jwksJson = await response.text();
// JWKSをキャッシュ
fs.writeFileSync(cacheFile, jwksJson);
console.log(`JWKSをキャッシュに保存: ${cacheFile}`);
return jwksJson;
}
async function main() {
console.log('=== Node.js JWT バリデーター ===');
console.log(`トークン: ${SAMPLE_JWT_TOKEN.substring(0, 50)}...`);
console.log(`JWKS URL: ${JWKS_URL}`);
console.log('');
try {
// JWKSをダウンロードしてキャッシュ
const jwksJson = await downloadAndCacheJWKS(JWKS_URL, JWKS_CACHE_FILE);
console.log("JWKSのダウンロードとキャッシュが成功しました");
// JWKSを解析し、キー座標を抽出
const jwks = JSON.parse(jwksJson);
if (!jwks.keys || jwks.keys.length === 0) {
throw new Error("JWKSにキーが見つかりません");
}
const key = jwks.keys[0];
// joseライブラリを使用して検証(推奨)
console.log('joseライブラリを使用中:');
const resultJose = await validateReferralTokenJose(SAMPLE_JWT_TOKEN, jwksJson);
if (resultJose.isValid) {
console.log('✅ トークンの検証に成功しました!');
console.log(`キャンペーンID: ${resultJose.campaignID}`);
console.log(`クリエイティブID: ${resultJose.creativeID}`);
console.log(`RCLID: ${resultJose.rclid}`);
console.log(`発行日時: ${resultJose.issuedAt.toISOString()}`);
} else {
console.error(`❌ トークンの検証に失敗しました: ${resultJose.error}`);
}
console.log('');
// 代替方法を表示
console.log('jsonwebtokenを使用した代替方法:');
console.log('注意: 適切なJWKからPEMへの変換が必要です');
const resultJWT = validateReferralTokenJWT(SAMPLE_JWT_TOKEN, jwksJson);
console.log(`結果: ${resultJWT.isValid ? '有効' : '無効'}`);
} catch (error) {
console.error(`❌ エラー: ${error.message}`);
}
}
// 他のモジュールで使用するための関数をエクスポート
module.exports = {
validateReferralTokenJose,
validateReferralTokenJWT
};
// このファイルが直接実行された場合、例を実行
if (require.main === module) {
main().catch(console.error);
}
入出力例
入力
- JWTトークン: 概要ページからテストトークンをコピー
- 公開鍵ソース:
https://public-api.rokt.com/.well-known/jwks.json
出力
=== Node.js JWT バリデーター ===
トークン: eyJhbGciOiJFUzI1NiIsImtpZCI6InJva3Qtc2lnbmluZy1rZXkiLCJ0eXAiOiJKV1QifQ...
JWKS URL: https://public-api.rokt.com/.well-known/jwks.json
JWKS をダウンロード中: https://public-api.rokt.com/.well-known/jwks.json
JWKS をキャッシュに保存: jwks_cache.json
JWKS のダウンロードとキャッシュが成功しました
jose ライブラリを使用:
✅ トークンの検証が成功しました!
キャンペーン ID: 3436085368692408324
クリエイティブ ID: 3437732754935906308
RCLID: 7db958dbd232247a4a8285a34d22fe0f4e9affa463bf5ee54e26721ab0df0e23
発行日時: 2025-08-20T05:10:01.000Z
jsonwebtoken を使用 した代替メソッド:
注意: 適切な JWK から PEM への変換が必要
結果: 無効
実行方法
- コードを
rokt_jwt_validator.jsに保存 - 依存関係をインストール:
npm install jose jsonwebtoken - 実行:
node rokt_jwt_validator.js
ES モジュールを使用した代替実装
ES モジュールを好む場合は、以下の構文を使用できます:
import { jwtVerify, importJWK } from 'jose';
// ... 残りのコードは同じです
ノート
-
joseライブラリは、最新の Node.js アプリケーションに推奨されます -
公開鍵は Rokt の JWKS エンドポイントから取得されます
-
この例では、署名検証に ECDSA-256 (ES256) アルゴリズムを使用しています
-
パフォーマンス向上のために公開鍵をキャッシュすることを検討してください
-
joseライブラリは、JWK から公開鍵への変換を自動的に処理します