authentication-patterns について
authentication-patternsは、認証の実装やレビューに使う開発者向けのリファレンススキルです。一般的な方式やプロバイダーの選定、トークンとパスワードの扱い、リリース前のセキュリティ確認項目を扱います。
主な機能
- 01セッション、JWT、OAuth、Passkeysの比較
- 02認証方式の選定ガイド
- 03JWTのライフサイクルと保存方法
- 04認証プロバイダーのパターン比較
- 05リリース前のセキュリティチェックリスト
活用シーン
- 01プロジェクトに適した認証方式の選定
- 02既存の認証フローのリスク確認
- 03認証方式の移行
- 04認証変更のリリース前チェック
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ zebbern/ claude-code-guide --skill authentication-patternsインストール後、Claude Code で/authentication-patternsを入力して読み込まれたか確認します。
詳細
認証パターンのスキル
安全で本番環境に対応した認証を実装するためのリファレンスです。
WHEN_TO_USE
プロジェクトで認証を実装する場合、既存の認証フローにセキュリティ上の問題がないか確認する場合、認証プロバイダーを選択する場合、または認証方式を移行する場合に、このスキルを適用してください。認証に関する変更をリリースする前に、セキュリティチェックリストを使用してください。
AUTH_APPROACHES
| アプローチ | 仕組み | 最適な用途 | デメリット |
|---|---|---|---|
| セッションベース | サーバーがセッションをDB/Redisに保存し、クライアントがセッションID Cookieを保持します | 従来型のサーバーレンダリングアプリ、即時失効が必要なアプリ | サーバー側のストレージが必要で、共有ストアなしでは水平スケーリングが困難です |
| JWT(ステートレス) | サーバーがトークンに署名し、クライアントがリクエストごとに送信します | APIファーストのアプリ、マイクロサービス、モバイルクライアント | ブロックリストなしでは失効できず、クレームが増えるとトークンサイズが大きくなります |
| OAuth 2.0 / OIDC | 外部プロバイダー(Google、GitHubなど)に認証を委任します | ソーシャルログイン、エンタープライズSSO、認証に関する責任の軽減 | フローがより複雑で、外部プロバイダーの可用性に依存します |
| パスキー / WebAuthn | 暗号鍵ペアを使用し、パスワードは不要です | 高セキュリティのアプリ、パスワードレスUX | 古いブラウザーではサポートが限られ、ユーザーへの説明が必要です |
選択ガイド
- シンプルな要件のサーバーレンダリングアプリ → セッションベース
- APIを呼び出すSPAまたはモバイルアプリ → リフレッシュトークンローテーションを伴うJWT
- ソーシャルログインまたはSSOを導入したい場合 → OAuth 2.0 / OIDC
- 最新のUXを目指す新規開発 → パスキー + OAuthへのフォールバック
JWT_BEST_PRACTICES
トークンのライフサイクル
Login → Access Token (short-lived) + Refresh Token (long-lived, rotated)
│
├─ Access Token: 15 min expiry, sent via httpOnly cookie or Authorization header
│
└─ Refresh Token: 7-30 day expiry, stored in httpOnly secure cookie
│
└─ On use: issue new access + new refresh token, invalidate old refresh token
ルール
- [P0-MUST] アクセストークンの有効期限を短く設定してください(15分以下)。
- [P0-MUST] トークンは
httpOnly、Secure、SameSite=LaxCookieに保存してください。localStorageやsessionStorageには絶対に保存しないでください。 - [P0-MUST] リフレッシュトークンローテーションを実装してください。各リフレッシュトークンは1回のみ使用できます。
- [P0-MUST] 失効したリフレッシュトークンを管理するサーバー側ブロックリストを維持してください。
- [P1-SHOULD] JWTペイロードには必須のクレーム(sub、iat、exp、role)のみを含めてください。小さく保ちましょう。
- [P1-SHOULD] 分散システムでは非対称署名(RS256またはES256)を使用し、単一サービスでは対称署名(HS256)を使用してください。
- [P1-SHOULD] すべてのリクエストで
iss、aud、expクレームを検証してください。 - [P2-MAY] トークンのペイロードに機密データが含まれる場合は、JWE(暗号化JWT)を使用してください。
トークン保存方法の比較
| 保存方法 | XSSへの安全性 | CSRFへの安全性 | 推奨事項 |
|---|---|---|---|
httpOnly Cookie | あり | なし(CSRFトークンが必要) | 推奨 |
localStorage | なし | あり | 認証トークンには絶対に使用しない |
sessionStorage | なし | あり | 認証トークンには絶対に使用しない |
| メモリー内(JS変数) | あり | あり | SPAでは問題ありませんが、更新すると失われます |
PROVIDER_PATTERNS
比較
| プロバイダー | 種類 | 最適な用途 | 料金 | 主な機能 |
|---|---|---|---|---|
| NextAuth / Auth.js | OSSライブラリ | 完全な制御を求めるNext.jsアプリ | 無料 | 80以上のプロバイダー、DBアダプター、セルフホスト可能 |
| Clerk | マネージドサービス | 迅速な立ち上げ、事前構築済みUI、ユーザー管理 | 無料プラン、その後はMAU単位 | すぐに使えるコンポーネント、ユーザーダッシュボード、組織サポート |
| Supabase Auth | マネージド(Supabaseの一部) | DB/ストレージにすでにSupabaseを使用しているアプリ | 無料プラン、その後はMAU単位 | 行レベルセキュリティとの統合、マジックリンク、SSO |
| Lucia | OSSライブラリ | 完全な制御、最小限の抽象化 | 無料 | セッションベース、フレームワーク非依存、型安全 |
各プロバイダーの使いどころ
- NextAuth / Auth.js:プロバイダーの柔軟性、セルフホスト、データベースセッションの制御が必要な場合に適しています。カスタムフローが必要な場合に最適です。
- Clerk:事前構築済みのUIコンポーネントを使って、認証をすばやく導入したい場合に適しています。MVPや、認証UIを構築したくないチームに最適です。
- Supabase Auth:すでにSupabaseを使用している場合に適しています。認証はRLSポリシーと統合され、行レベルセキュリティを実現します。
- Lucia:フレームワークに縛られず、最小限で型安全なセッションライブラリを使いたい場合に適しています。
NextAuth.jsのセットアップパターン
// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { prisma } from "@/lib/prisma";
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GitHub({
clientId: process.env.GITHUB_CLIENT_ID!,
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
}),
],
callbacks: {
session({ session, user }) {
session.user.id = user.id;
return session;
},
},
});
SECURITY_CHECKLIST
認証をリリースする前に
- レート制限:ログインエンドポイントの試行回数を、IP ごとに 1 分あたり 5~10 回に制限します。
- CSRF 対策:状態を変更するすべてのリクエストで CSRF 対策トークンを使用します(または
SameSite=LaxCookie を使用します)。 - パスワードのハッシュ化:bcrypt(コスト 12 以上)または argon2id を使用します。MD5、SHA-1、プレーンな SHA-256 は決して使用しません。
- HTTPS のみを使用:すべての認証エンドポイントを TLS 経由で提供します。Cookie には
Secureフラグを設定します。 - 入力の検証:メールアドレスの形式、パスワードの長さ(最小 8 文字、最大 128 文字)を検証し、SQL/NoSQL インジェクションの脆弱性がないことを確認します。
- アカウントの列挙対策:アカウントの有無にかかわらず、ログインと登録で同じレスポンスを返します。
- セッションの無効化:ログアウト時にクライアント Cookie だけでなく、サーバー側のセッション/リフレッシュトークンも無効化します。
- MFA のサポート:機密性の高いアカウントでは、2 つ目の要素として TOTP(認証アプリ)または WebAuthn を使用します。
- パスワードのリセット:有効期限付きトークン(1 時間)を使用し、トークンは 1 回限りとし、安全なチャネルで送信します。
- 監査ログ:認証イベント(ログイン、ログアウト、失敗した試行、パスワード変更)をタイムスタンプと IP アドレスとともに記録します。
パスワードのハッシュ化
// Using bcrypt
import bcrypt from "bcrypt";
const SALT_ROUNDS = 12;
async function hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, SALT_ROUNDS);
}
async function verifyPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}
// Using argon2 (preferred for new projects)
import argon2 from "argon2";
async function hashPassword(password: string): Promise<string> {
return argon2.hash(password, { type: argon2.argon2id });
}
async function verifyPassword(hash: string, password: string): Promise<boolean> {
return argon2.verify(hash, password);
}
よくある間違い
| 間違い | リスク | 対策 |
|---|---|---|
JWT を localStorage に保存する | XSS によりトークンが盗まれる可能性があります | httpOnly Cookie を使用します |
| 有効期間の長い JWT(数日/数週間) | 盗まれたトークンが長期間有効になります | 15 分のアクセストークンとリフレッシュトークンのローテーションを使用します |
| CSRF 対策がない | 攻撃者が別のサイトからリクエストを偽造できます | SameSite=Lax Cookie と CSRF トークンを使用します |
| パスワード要件が弱い | 総当たり攻撃やクレデンシャルスタッフィングの危険があります | 最小 8 文字とし、流出したパスワードのリストと照合します |
| ログイン時にユーザーの存在を明かす | アカウントの列挙につながります | 汎用的な「認証情報が無効です」というメッセージを使用します |
| リフレッシュトークンをローテーションしない | 盗まれたリフレッシュトークンで無期限にアクセスできます | ローテーション付きの使い捨てリフレッシュトークンを使用します |
| ソースコードにシークレットをハードコードする | git の履歴から認証情報が漏えいする可能性があります | 環境変数を使用し、シークレットは決してコミットしません |
| ログインのレート制限がない | 総当たり攻撃を受ける危険があります | IP ごとに 1 分あたり 5~10 回に制限し、指数バックオフを適用します |
| 独自の暗号方式を実装する | 気づきにくい脆弱性が生じます | 実績のあるライブラリ(bcrypt、argon2、jose)を使用します |
| JWT のクレームを検証しない | サービス間でトークンが不正に使用される可能性があります | 常に iss、aud、exp を検証します |
コメント
Markdown 対応