認可コードフロー - 認可コードフロー
サーバーサイドアプリ向けの最も安全な OAuth 2.0 フロー。認可コードをバックチャネルでトークンに交換する。
概念図
実例
認可リクエスト URL の構築例。state パラメータで CSRF を防止する
GET /authorize?
response_type=code
&client_id=CLIENT_ID
&redirect_uri=https://app.example.com/callback
&scope=read write
&state=xyz123randomトークンエンドポイントへの POST リクエスト。認可コードをアクセストークンに交換する
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTH_CODE_FROM_CALLBACK
&redirect_uri=https://app.example.com/callback
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRETstate パラメータによる CSRF 対策の実装例
// state パラメータの生成と検証
const state = crypto.randomBytes(32).toString("hex");
req.session.oauthState = state;
// 認可リクエストに state を含める
// コールバック時の検証
if (req.query.state !== req.session.oauthState) {
throw new Error("State mismatch - possible CSRF attack");
}フローの全体像
認可コードフローは以下の 4 ステップで構成されます。
認可リクエスト: クライアントがユーザーを認可サーバーの
/authorizeエンドポイントにリダイレクトする。response_type=code、client_id、redirect_uri、scope、stateを含める認可コードの発行: ユーザーが同意すると、認可サーバーが
redirect_uriに認可コード(code)を付与してリダイレクトする。認可コードは短命(通常 10 分以内)で一回限り有効トークン交換(バックチャネル): クライアントのサーバーが認可コードと
client_secretを使い、認可サーバーの/tokenエンドポイントに POST リクエストを送信する。この通信はサーバー間(バックチャネル)で行われるため、ブラウザにトークンが露出しないリソースアクセス: 取得したアクセストークンを
Authorization: Bearerヘッダに含め、リソースサーバーの API にアクセスする
セキュリティ上の注意点
state パラメータの検証: 認可リクエスト時にランダムな
state値を生成してセッションに保存し、コールバック時に一致を検証する。これを省略すると CSRF 攻撃により攻撃者のアカウントと紐付けられる危険があるredirect_uri の厳密な固定: 認可サーバーに登録した
redirect_uriと完全一致させる。部分一致やワイルドカードを許可すると、オープンリダイレクタ経由で認可コードが漏洩する認可コードの一回限り使用: 認可コードは一度トークンに交換したら無効化する。再利用が検出された場合は、そのコードで発行済みのトークンもすべて失効させるべき(RFC 6749 Section 4.1.2)
client_secret の保護: クライアントシークレットはサーバーサイドのみで保持し、フロントエンドやバージョン管理に含めない。環境変数やシークレットマネージャーで管理する
HTTPS の強制: 認可コードやトークンの通信はすべて HTTPS で行う。HTTP での通信は中間者攻撃によるトークン漏洩のリスクがある
