リフレッシュトークン
メソッド
REST メソッドを採用しています。
HTTP メソッド
POST: トークン更新
命名規則
クエリパラメータとノードの命名を統一し、可読性を向上させるため、リクエスト時の URI と JSON 内のノードには snake_case を使用します。
リクエストとレスポンス
ヘッダー
メタ情報はレスポンスボディではなく、HTTP ヘッダーに設定されます。
リクエストヘッダー
Content-Type:application/json
レスポンスヘッダー
Content-Type:application/json
リフレッシュトークン
URI
リクエストボディ
リクエストボディは JSON です。
管理者用 Cognito アプリクライアントに クライアントシークレット(COGNITO_ADMIN_CLIENT_SECRET)がある場合、Cognito は正しい SECRET_HASH を要求します。これはユーザー名文字列から計算されます。実運用では、ログイン(または /me)レスポンスの cognito_sub(JWT の sub)を送ることを推奨します。ユーザープールの設定によっては email のみでは拒否されることがあります(メールエイリアスでのサインインなど)。両方送る場合、ハッシュ計算には cognito_sub を優先します。
{
"refresh_token": "eyJjdGkiOiI0YjM1ZjQ2NS0yM2E0LTRiZTAtYjM2Mi01...",
"email": "admin@example.com",
"cognito_sub": "1111-aaaa-2222-bbbb-3333-cccc4444dddd"
}
バリデーションルール
| フィールド | ルール |
|---|---|
| refresh_token | 必須。空でない文字列であること。 |
任意。メール形式。クライアントシークレットがある場合は、cognito_sub と 少なくともどちらか一方が必須。 |
|
| cognito_sub | 任意。空でない文字列。ログイン / JWT のユーザー sub。コンフィデンシャルクライアント(シークレットあり)では推奨。 |
レスポンス(200 OK)
レスポンスは JSON です。
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJjdGkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ...",
"user": {
"id": 1,
"name": "Admin User",
"cognito_sub": "1111-aaaa-2222-bbbb",
"email": "admin@example.com",
"role": {
"id": 1,
"name": "admin"
}
}
}
Cognito が新しいリフレッシュトークンを返さない場合、refresh_token は省略されることがあります。
認証要件
このエンドポイントは認証を要求しません。リクエストボディにリフレッシュトークンを含めます。Authorization ヘッダーは不要です。
例外処理
例外時のステータスコードは次のとおりです。
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| リクエストボディが不正、またはバリデーションエラー | 400 | Bad Request |
| リフレッシュトークンが無効または期限切れ | 401 | Unauthorized |
アプリクライアントにシークレットがあるのに email と cognito_sub の両方が欠けている |
401 | Unauthorized |
更新後の ID トークンから必須クレームが取得できない(email や sub など) |
401 | Unauthorized |
| 管理者が見つかりません | 401 | Unauthorized |
| サーバ内部エラー | 500 | Internal Server Error |
処理フロー
シーケンス図
sequenceDiagram
participant Client
participant API as Hono Router
participant Validate as Zod Validation
participant Service as Auth Service
participant Cognito as AWS Cognito
participant DB as PostgreSQL Database
Client->>API: POST /api/v1/auth/refresh_token
API->>Validate: Validate body (refresh_token, optional email, cognito_sub)
Validate-->>API: Validation passed
API->>Service: refreshToken(refresh_token, email, cognito_sub, ip, user_agent)
Service->>Cognito: initiateAuth(REFRESH_TOKEN_AUTH, SECRET_HASH if client secret)
alt Token Refresh Success
Cognito-->>Service: New Access Token + ID Token
Service->>Service: Verify ID token, extract sub and email
Service->>DB: Find admin by cognito_sub
DB-->>Service: Admin record
Service->>DB: Create session (hashed token, ip, user_agent, expires_at)
DB-->>Service: Session created
Service-->>API: { token, refresh_token?, user }
API-->>Client: 200 OK { token, refresh_token?, user }
else Token Refresh Failed
Cognito-->>Service: NotAuthorizedException
Service-->>API: throw UnauthorizedError
API-->>Client: 401 Unauthorized
end
Routes 層
ルーティングはここで行います。Zod スキーマでリクエストボディを検証し、クライアント IP と User-Agent を取り出してから認証サービスに委譲します。
ソース: src/routes/v1/auth.ts
Services 層
ビジネスロジックの説明です。クライアントシークレットがある場合は SECRET_HASH 用のユーザー名文字列を解決します(cognito_sub を優先、なければ正規化した email)。続けて Cognito の REFRESH_TOKEN_AUTH を呼び出し、新しい ID トークンを検証して管理者情報を抽出し、データベースにセッションを作成し、新しいアクセストークン・(あれば)新しいリフレッシュトークン・ユーザー情報を返します。
ソース: src/services/auth.ts
Repositories 層
データベースおよび外部サービスへのアクセスです。Cognito の InitiateAuthCommand(REFRESH_TOKEN_AUTH)でリフレッシュを行い、SECRET_HASH は呼び出し側が渡したユーザー名文字列から計算します(リフレッシュトークン文字列そのものではありません)。Cognito sub による管理者検索、アクセストークンの SHA-256 ハッシュを用いたセッション作成を扱います。
ソース: src/repositories/
セキュリティ
- リフレッシュトークンは使い捨てです。更新のたびに新しいリフレッシュトークンが発行されます
- コンフィデンシャルクライアントでは
cognito_sub(またはプールで有効な email)を送り、SECRET_HASHを Cognito と一致させます。ログイン時に得たcognito_subをリフレッシュトークンと一緒に保持してください - サインイン用 email はパスワード/パスワードリセット系フローで正規化(trim + 小文字化)され、
USERNAME/SECRET_HASHの一貫性が保たれます - クライアント IP アドレスと User-Agent は監査用に記録されます
- セッショントークンはデータベースに SHA-256 ハッシュで保存されます
- 更新失敗はリクエストコンテキスト付きでログに記録されます
- 期限切れまたは失効したリフレッシュトークンは Cognito によって拒否されます