jwt-authentication について
Node.js アプリケーションに JWT 認証を導入するための学習・実装ガイドです。登録、ログイン、保護されたルートに加え、トークン更新やロールベースアクセス制御も扱います。
主な機能
- 01JWT の生成と検証
- 02ユーザー登録とパスワード確認
- 03ミドルウェアによるルート保護
- 04トークン更新と有効期限管理
- 05ロールベースアクセス制御
活用シーン
- 01Node.js REST API への認証追加
- 02JWT によるアプリケーションルートの保護
- 03トークン更新とアクセス制御フローの構築
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ pluginagentmarketplace/ custom-plugin-nodejs --skill jwt-authenticationインストール後、Claude Code で/jwt-authenticationを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/config.yamlreferences/GUIDE.mdscripts/helper.py詳細
JWT 認証スキル
JSON Web Token を使用して、Node.js アプリケーションにセキュアでスケーラブルな認証を実装します。
クイックスタート
JWT 認証を 4 つのステップで実装します。
- インストール -
npm install jsonwebtoken bcryptjs - 登録 - パスワードをハッシュ化し、ユーザーを作成してトークンを生成します
- ログイン - パスワードを検証してトークンを生成します
- 保護 - ミドルウェアでトークンを検証します
基本概念
JWT の生成
const jwt = require('jsonwebtoken');
function generateToken(userId) {
return jwt.sign(
{ id: userId },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
);
}
function generateRefreshToken(userId) {
return jwt.sign(
{ id: userId },
process.env.JWT_REFRESH_SECRET,
{ expiresIn: '7d' }
);
}
ユーザー登録
const bcrypt = require('bcryptjs');
async function register(req, res) {
const { email, password, name } = req.body;
// Check if user exists
const existingUser = await User.findOne({ email });
if (existingUser) {
return res.status(409).json({ error: 'User already exists' });
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 10);
// Create user
const user = await User.create({
email,
password: hashedPassword,
name
});
// Generate tokens
const accessToken = generateToken(user._id);
const refreshToken = generateRefreshToken(user._id);
res.status(201).json({
user: { id: user._id, email, name },
accessToken,
refreshToken
});
}
ユーザーログイン
async function login(req, res) {
const { email, password } = req.body;
// Find user
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Verify password
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Generate tokens
const accessToken = generateToken(user._id);
const refreshToken = generateRefreshToken(user._id);
res.json({
user: { id: user._id, email: user.email },
accessToken,
refreshToken
});
}
認証ミドルウェア
async function authenticate(req, res, next) {
try {
// Get token from header
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: 'No token provided' });
}
const token = authHeader.split(' ')[1];
// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// Get user
const user = await User.findById(decoded.id).select('-password');
if (!user) {
return res.status(401).json({ error: 'User not found' });
}
req.user = user;
next();
} catch (error) {
res.status(401).json({ error: 'Invalid token' });
}
}
// Usage
router.get('/profile', authenticate, getProfile);
学習パス
初級(1~2 週間)
- ✅ JWT の構造を理解する
- ✅ 登録とログインを実装する
- ✅ 認証ミドルウェアを作成する
- ✅ ルートを保護する
中級(3~4 週間)
- ✅ リフレッシュトークンのフロー
- ✅ ロールベースのアクセス制御
- ✅ パスワードリセットのフロー
- ✅ トークンのブラックリスト化
上級(5~6 週間)
- ✅ OAuth の統合
- ✅ 二要素認証
- ✅ セッション管理
- ✅ セキュリティのベストプラクティス
高度なパターン
ロールベースのアクセス制御
const authorize = (...roles) => {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: 'Not authenticated' });
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
next();
};
};
// Usage
router.delete('/users/:id',
authenticate,
authorize('admin', 'moderator'),
deleteUser
);
トークンの更新
async function refreshAccessToken(req, res) {
const { refreshToken } = req.body;
try {
const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET);
// Verify refresh token exists in database
const stored = await RefreshToken.findOne({
token: refreshToken,
userId: decoded.id
});
if (!stored) {
return res.status(401).json({ error: 'Invalid refresh token' });
}
// Generate new access token
const accessToken = generateToken(decoded.id);
res.json({ accessToken });
} catch (error) {
res.status(401).json({ error: 'Token refresh failed' });
}
}
パスワードリセットのフロー
async function requestPasswordReset(req, res) {
const { email } = req.body;
const user = await User.findOne({ email });
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
// Generate reset token (short expiry)
const resetToken = jwt.sign(
{ id: user._id, purpose: 'reset' },
process.env.JWT_SECRET,
{ expiresIn: '15m' }
);
// Send email with reset link
await sendResetEmail(user.email, resetToken);
res.json({ message: 'Reset email sent' });
}
async function resetPassword(req, res) {
const { token, newPassword } = req.body;
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
if (decoded.purpose !== 'reset') {
return res.status(400).json({ error: 'Invalid token' });
}
const hashedPassword = await bcrypt.hash(newPassword, 10);
await User.findByIdAndUpdate(decoded.id, { password: hashedPassword });
res.json({ message: 'Password reset successful' });
} catch (error) {
res.status(400).json({ error: 'Invalid or expired token' });
}
}
セキュリティのベストプラクティス
- ✅ 強力な JWT シークレットを使用します(32 文字以上のランダムな文字列)
- ✅ アクセストークンの有効期限を短く設定します(15 分~1 時間)
- ✅ リフレッシュトークンの有効期限を長めに設定します(7 日~30 日)
- ✅ リフレッシュトークンをデータベースに保存します
- ✅ bcrypt でパスワードをハッシュ化します(10 ラウンド以上)
- ✅ 本番環境では HTTPS を使用します
- ✅ レート制限を実装します
- ✅ すべての入力を検証します
- ✅ 機密データを JWT ペイロードに保存しないでください
JWT の構造
header.payload.signature
Header (base64):
{
"alg": "HS256",
"typ": "JWT"
}
Payload (base64):
{
"id": "user123",
"iat": 1516239022,
"exp": 1516242622
}
Signature:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
一般的な JWT クレーム
iss- 発行者sub- サブジェクト(ユーザー ID)aud- 対象者exp- 有効期限iat- 発行日時nbf- 有効期間の開始日時
使用する場面
次のような場合に JWT 認証を使用します。
- ステートレスな REST API を構築する場合
- スケーラビリティが必要な場合(サーバー側のセッションなし)
- モバイルアプリの認証
- マイクロサービスアーキテクチャ
- シングルサインオン(SSO)
関連スキル
- Express REST API(API エンドポイントを保護)
- データベース統合(ユーザーを保存)
- テストとデバッグ(認証フローをテスト)
- パフォーマンス最適化(トークンのキャッシュ)
リソース
コメント
Markdown 対応