jwt-handler
JWT(JSON Web Token)の生成、検証、更新、デバッグなど、セキュアなトークン管理に関する要望に対応し、アクセスやリフレッシュトークンのライフサイクルを安全に制御するSkill。
📜 元の英語説明(参考)
When the user needs to generate, validate, refresh, or debug JSON Web Tokens. Use when the user mentions "JWT," "access token," "refresh token," "token rotation," "token expiration," "token validation," "bearer token," or "decode JWT." Handles secure token lifecycle including signing, verification, refresh rotation, and revocation. For full auth system design, see auth-system-setup.
🇯🇵 日本人クリエイター向け解説
JWT(JSON Web Token)の生成、検証、更新、デバッグなど、セキュアなトークン管理に関する要望に対応し、アクセスやリフレッシュトークンのライフサイクルを安全に制御するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o jwt-handler.zip https://jpskill.com/download/15030.zip && unzip -o jwt-handler.zip && rm jwt-handler.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/15030.zip -OutFile "$d\jwt-handler.zip"; Expand-Archive "$d\jwt-handler.zip" -DestinationPath $d -Force; ri "$d\jwt-handler.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
jwt-handler.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
jwt-handlerフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
JWTハンドラー
概要
Webアプリケーション向けのセキュアなJWTトークンのライフサイクル(生成、検証、リフレッシュローテーション、失効、デバッグ)を実装します。短い有効期間のアクセストークン、ファミリートラッキングによるワンタイムリフレッシュローテーション、適切なキー管理など、現在のセキュリティのベストプラクティスに従ったコードを生成します。
手順
トークン生成
JWTトークンを作成する際:
- アクセストークン: 短い有効期間(15分)、ユーザーIDとロールを含み、RS256またはES256で署名
- リフレッシュトークン: 長い有効期間(7〜30日)、opaqueまたはJWT、ハッシュ化してデータベースに保存
- 本番環境では常に非対称署名(RS256/ES256)を使用 - 秘密鍵なしで検証が可能
- 最小限のペイロード: ユーザーID、ロール、発行日時、有効期限。PII(個人情報)、シークレットは含めない。
// アクセストークンのペイロード — 最小限に保つ
{
sub: "user_abc123",
roles: ["member"],
iat: 1708185600,
exp: 1708186500 // 15分
}
リフレッシュトークンローテーション
再利用検出によるワンタイムローテーションを実装します。
- 各リフレッシュトークンは「ファミリー」(チェーン内の最初のトークン)に属する
- リフレッシュ時:古いトークンを無効化し、新しいアクセス+リフレッシュペアを発行
- 失効したトークンが提示された場合 → そのファミリー内のすべてのトークンを失効させる(盗難を検出)
- データベースに保存:token_hash、family_id、user_id、expires_at、revoked_at
トークン検証ミドルウェア
1. Authorizationヘッダーからトークンを抽出(Bearerスキーム)
2. 公開鍵を使用して署名を検証
3. 有効期限(expクレーム)を確認
4. 発行者と対象者が設定されている場合は確認
5. デコードされたペイロードをリクエストコンテキストにアタッチ
6. 特定のエラー(expired、invalid、missing)とともに401を返す
キー管理
- RSA 2048+またはEC P-256キーペアを生成
- 秘密鍵を環境変数またはシークレットマネージャーに保存
- 公開鍵を /.well-known/jwks.json エンドポイント経由で公開
- キーローテーションをサポート:トークンヘッダーにキーID(kid)を含める
例
例1:Node.jsトークンサービス
プロンプト: 「Expressアプリ用のリフレッシュローテーションを備えたJWTトークンサービスを作成してください」
出力:
// token.service.ts
import jwt from 'jsonwebtoken';
import crypto from 'crypto';
export class TokenService {
generateAccessToken(user: User): string {
return jwt.sign(
{ sub: user.id, roles: user.roles },
process.env.JWT_PRIVATE_KEY,
{ algorithm: 'RS256', expiresIn: '15m', issuer: 'app' }
);
}
async generateRefreshToken(userId: string, familyId?: string): Promise<string> {
const token = crypto.randomBytes(32).toString('hex');
const hash = crypto.createHash('sha256').update(token).digest('hex');
await db.refreshTokens.create({
tokenHash: hash,
userId,
familyId: familyId || crypto.randomUUID(),
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
});
return token;
}
async rotateRefreshToken(oldToken: string) {
const hash = crypto.createHash('sha256').update(oldToken).digest('hex');
const stored = await db.refreshTokens.findByHash(hash);
if (!stored || stored.revokedAt) {
// 再利用を検出 — ファミリー全体を失効
if (stored) await db.refreshTokens.revokeFamily(stored.familyId);
throw new TokenReuseError();
}
await db.refreshTokens.revoke(stored.id);
const newRefresh = await this.generateRefreshToken(stored.userId, stored.familyId);
const user = await db.users.findById(stored.userId);
const newAccess = this.generateAccessToken(user);
return { accessToken: newAccess, refreshToken: newRefresh };
}
}
例2:JWTトークンのデバッグ
プロンプト: 「このJWTが機能しません。デコードできますか? eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImV4cCI6MTcwODE4NTYwMH0.abc...」
出力:
デコードされたJWT:
Header: { alg: "RS256" }
Payload: { sub: "user_123", exp: 1708185600 }
見つかった問題: トークンは2024-02-17T12:00:00Z(3時間前)に失効しました。
トークンには "iat" クレームがありません — 監査ログのために追加することを検討してください。
"iss" または "aud" クレームがありません — 複数サービスの設定ではこれらを追加することをお勧めします。
ガイドライン
- 弱いシークレットでHS256を使用しないでください — RS256/ES256または256+ビットのランダムキーでHS256を使用してください
- localStorageにアクセストークンを保存しないでください — メモリ変数を使用してください。httpOnlyクッキーにリフレッシュトークンを保存してください
- データベースに保存する前に、常にリフレッシュトークンをハッシュ化してください — SHA-256で十分です
- トークンの有効期間のチェックと監査ログのために"iat"クレームを含めてください
- サービス間の検証のためにクロックスキュー許容値を30秒に設定してください
- クライアント側の処理を容易にするために特定の401エラー("token_expired," "token_invalid," "token_missing")を返してください
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
JWT Handler
Overview
Implements secure JWT token lifecycle for web applications — generation, validation, refresh rotation, revocation, and debugging. Produces code that follows current security best practices including short-lived access tokens, one-time refresh rotation with family tracking, and proper key management.
Instructions
Token Generation
When creating JWT tokens:
- Access token: Short-lived (15 min), contains user ID and roles, signed with RS256 or ES256
- Refresh token: Longer-lived (7-30 days), opaque or JWT, stored hashed in database
- Always use asymmetric signing (RS256/ES256) for production — allows verification without the private key
- Minimal payload: user ID, roles, issued-at, expiration. No PII, no secrets.
// Access token payload — keep it minimal
{
sub: "user_abc123",
roles: ["member"],
iat: 1708185600,
exp: 1708186500 // 15 minutes
}
Refresh Token Rotation
Implement one-time rotation with reuse detection:
- Each refresh token belongs to a "family" (first token in chain)
- On refresh: invalidate old token, issue new access + refresh pair
- If a revoked token is presented → revoke ALL tokens in that family (theft detected)
- Store in database: token_hash, family_id, user_id, expires_at, revoked_at
Token Validation Middleware
1. Extract token from Authorization header (Bearer scheme)
2. Verify signature using public key
3. Check expiration (exp claim)
4. Check issuer and audience if configured
5. Attach decoded payload to request context
6. Return 401 with specific error: expired, invalid, missing
Key Management
- Generate RSA 2048+ or EC P-256 key pairs
- Store private key in environment variable or secrets manager
- Expose public key via /.well-known/jwks.json endpoint
- Support key rotation: include key ID (kid) in token header
Examples
Example 1: Node.js Token Service
Prompt: "Create a JWT token service with refresh rotation for my Express app"
Output:
// token.service.ts
import jwt from 'jsonwebtoken';
import crypto from 'crypto';
export class TokenService {
generateAccessToken(user: User): string {
return jwt.sign(
{ sub: user.id, roles: user.roles },
process.env.JWT_PRIVATE_KEY,
{ algorithm: 'RS256', expiresIn: '15m', issuer: 'app' }
);
}
async generateRefreshToken(userId: string, familyId?: string): Promise<string> {
const token = crypto.randomBytes(32).toString('hex');
const hash = crypto.createHash('sha256').update(token).digest('hex');
await db.refreshTokens.create({
tokenHash: hash,
userId,
familyId: familyId || crypto.randomUUID(),
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
});
return token;
}
async rotateRefreshToken(oldToken: string) {
const hash = crypto.createHash('sha256').update(oldToken).digest('hex');
const stored = await db.refreshTokens.findByHash(hash);
if (!stored || stored.revokedAt) {
// Reuse detected — revoke entire family
if (stored) await db.refreshTokens.revokeFamily(stored.familyId);
throw new TokenReuseError();
}
await db.refreshTokens.revoke(stored.id);
const newRefresh = await this.generateRefreshToken(stored.userId, stored.familyId);
const user = await db.users.findById(stored.userId);
const newAccess = this.generateAccessToken(user);
return { accessToken: newAccess, refreshToken: newRefresh };
}
}
Example 2: Debug a JWT Token
Prompt: "This JWT isn't working, can you decode it? eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImV4cCI6MTcwODE4NTYwMH0.abc..."
Output:
Decoded JWT:
Header: { alg: "RS256" }
Payload: { sub: "user_123", exp: 1708185600 }
Issue found: Token expired at 2024-02-17T12:00:00Z (3 hours ago).
The token has no "iat" claim — consider adding it for audit logging.
No "iss" or "aud" claims — recommend adding these for multi-service setups.
Guidelines
- Never use HS256 with a weak secret — use RS256/ES256 or HS256 with 256+ bit random key
- Never store access tokens in localStorage — use memory variables; refresh tokens in httpOnly cookies
- Always hash refresh tokens before database storage — SHA-256 is sufficient
- Include "iat" claim for token age checks and audit logging
- Set clock skew tolerance to 30 seconds for verification across services
- Return specific 401 errors: "token_expired," "token_invalid," "token_missing" — helps client-side handling