はじめに
「Googleでログイン」「GitHubでログイン」
日常的に使っているこのボタン、裏側で何が起きているか 説明できますか?
実はこのボタンの裏では OAuth 2.0 というプロトコルが動いています。OAuth 2.0 を理解すると、認証・認可の設計が格段にクリアになります。
この記事では、OAuth 2.0 の中でも最も安全とされる 認可コードフロー を中心に、図解で一歩ずつ解説します。
この記事は 「図解でわかるWeb技術の仕組み」シリーズ の第3回です。
第2回:Cookie・Session・JWTの違いを先に読むと、よりスムーズに理解できます。
1. OAuth 2.0 とは
認証と認可の違い
まず、混同しやすい2つの概念を整理します。
| 意味 | 英語 | 例 | |
|---|---|---|---|
| 認証 | 「あなたは誰?」を確認する | Authentication | ログイン(ID/パスワード) |
| 認可 | 「何をしていいか」を許可する | Authorization | 「プロフィール情報の読み取りを許可」 |
OAuth 2.0 は「認可」の仕組みです。 「認証」ではありません。
「OAuth = ログイン」は厳密には間違い
OAuth 2.0 自体はログイン(認証)の仕様ではなく、「データへのアクセス権を委譲する」仕様です。ログイン機能として使う場合は、OAuth 2.0 の上に構築された OpenID Connect(OIDC) を使います。
OAuth 2.0 の全体像
OAuth 2.0 の登場人物は 4つのロール です。
| ロール | 役割 | 具体例 |
|---|---|---|
| リソースオーナー | データの持ち主 | ユーザー(あなた) |
| クライアント | データを使いたいアプリ | 第三者のWebアプリ |
| 認可サーバー | 許可を出す窓口 | Google, GitHub |
| リソースサーバー | 実際のデータを持つサーバー | Google API, GitHub API |
2. 認可コードフロー ― OAuth 2.0 の標準パターン
OAuth 2.0 にはいくつかのフローがありますが、最もセキュアで推奨される のが 認可コードフロー(Authorization Code Flow) です。
フローの詳細
STEP 1: 認可リクエスト
https://accounts.google.com/o/oauth2/v2/auth?
response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://myapp.com/callback
&scope=profile email
&state=xyz123
| パラメータ | 意味 |
|---|---|
response_type=code |
認可コードを要求する |
client_id |
アプリの識別子(事前に登録) |
redirect_uri |
認可後のリダイレクト先 |
scope |
アクセスしたい範囲 |
state |
CSRF対策のランダム文字列 |
STEP 2: トークン取得
POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=https://myapp.com/callback
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
認可コードは 1回だけ使えるワンタイムコード です。使用後は無効になります。
STEP 3: リソースアクセス
GET /userinfo HTTP/1.1
Authorization: Bearer ACCESS_TOKEN
3. アクセストークンとリフレッシュトークン
なぜ2種類のトークンがあるのか
セキュリティと利便性のバランスを取るためです。
アクセストークンだけの場合:
├── 有効期限を長くする → 漏洩時の被害が大きい
└── 有効期限を短くする → 頻繁に再ログインが必要
解決策: 2種類のトークンを使い分ける
├── アクセストークン → 短命(15分〜1時間)で頻繁に使う
└── リフレッシュトークン → 長命で、新しいアクセストークンの発行にのみ使う
リフレッシュトークンの流れ
# アクセストークンが期限切れ → 401 Unauthorized
# リフレッシュトークンで新しいアクセストークンを取得
POST /token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
リフレッシュトークンのローテーション
セキュリティをさらに高めるため、リフレッシュトークンを使うたびに新しいリフレッシュトークンも一緒に発行する(古いものは無効化する)パターンが推奨されています。
4. スコープ(scope)― アクセス範囲を制限する
スコープは 「何に対するアクセスを許可するか」 を細かく制御する仕組みです。
スコープのリクエスト例
scope=profile email → プロフィールとメールだけ読める
scope=repo → リポジトリの読み書き
scope=read:user → ユーザー情報の読み取りのみ
最小権限の原則
スコープは必要最小限にする
アプリが「プロフィール情報」しか必要ないのに scope=repo(リポジトリの読み書き)を要求すると、ユーザーの信頼を失います。必要な権限だけを要求する のがOAuth 2.0の正しい使い方です。
5. セキュリティ対策
PKCE(Proof Key for Code Exchange)
PKCEは特にSPAやモバイルアプリで必須のセキュリティ対策です。
// 1. ランダムな code_verifier を生成
const codeVerifier = generateRandomString(128);
// 2. SHA-256ハッシュを取って code_challenge を作成
const codeChallenge = base64url(sha256(codeVerifier));
// 3. 認可リクエストに code_challenge を含める
const authUrl = `https://auth.example.com/authorize?
response_type=code
&client_id=YOUR_CLIENT_ID
&code_challenge=${codeChallenge}
&code_challenge_method=S256`;
// 4. トークンリクエストに code_verifier を含める
const tokenResponse = await fetch('/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authorizationCode,
code_verifier: codeVerifier // ← 元の値を送る
})
});
state パラメータ
// リクエスト時: ランダムな state を生成して保存
const state = generateRandomString(32);
sessionStorage.setItem('oauth_state', state);
// コールバック時: state が一致するか検証
const returnedState = new URL(window.location).searchParams.get('state');
if (returnedState !== sessionStorage.getItem('oauth_state')) {
throw new Error('CSRF攻撃の可能性');
}
6. OAuth 2.0 のフロー一覧
認可コードフロー以外にもフローがありますが、現在は 認可コードフロー + PKCE が推奨されています。
| フロー | 特徴 | 推奨度 |
|---|---|---|
| 認可コードフロー | サーバーサイドアプリ向け。最もセキュア | 推奨 |
| 認可コード + PKCE | SPA・モバイルアプリ向け。client_secret 不要 | 推奨 |
| インプリシットフロー | SPA向けだったが、トークンがURLに露出する | 非推奨 |
| クライアントクレデンシャル | マシン間通信向け(ユーザー関与なし) | 用途次第 |
| リソースオーナーパスワード | パスワードを直接渡す。OAuth以前の方式 | 非推奨 |
インプリシットフローは使わない
かつてはSPA向けに推奨されていましたが、アクセストークンがURLフラグメントに露出するため、現在は 認可コードフロー + PKCE に置き換えられています。
7. 実務での使いどころ
「Googleでログイン」の実装例(概要)
1. Google Cloud Console でOAuthクライアントIDを取得
2. ユーザーをGoogleの認可エンドポイントにリダイレクト
3. ユーザーが同意 → 認可コードが返る
4. 認可コードをトークンと交換
5. アクセストークンで Google UserInfo API を呼ぶ
6. メールアドレスで自アプリのユーザーと紐付け
よくあるミス
| ミス | 正しい対応 |
|---|---|
| state パラメータを省略 | 必ず検証する(CSRF対策) |
| redirect_uri を検証しない | 完全一致で検証する |
| アクセストークンをlocalStorageに保存 | HttpOnly Cookie に格納する |
| スコープを広く取りすぎる | 必要最小限にする |
8. まとめ
| 項目 | ポイント |
|---|---|
| OAuth 2.0 の目的 | パスワードを渡さずにデータアクセスを委譲する「認可」の仕組み |
| 認可コードフロー | 認可コード → トークン交換の2段階方式。最もセキュア |
| アクセストークン | リソースへのアクセス許可証。短命(15分〜1時間) |
| リフレッシュトークン | アクセストークンの再発行用。長命で認可サーバーにのみ送信 |
| スコープ | アクセス範囲の制限。最小権限の原則を守る |
| PKCE | 認可コードの横取り防止。SPA・モバイルでは必須 |
次回予告
第4回では 「DNS解決の流れ」 を図解で解説します。ブラウザに example.com と入力してからIPアドレスが返ってくるまで、裏側で何が起きているのか ― 再帰的問い合わせとキャッシュの仕組みをたどります。
シリーズ目次
| # | テーマ |
|---|---|
| 1 | HTTPリクエスト/レスポンスの仕組み |
| 2 | Cookie・Session・JWTの違い |
| 3 | OAuth 2.0 の仕組み(この記事) |
| 4 | DNS解決の流れ |
| 5 | HTTPS・TLS通信の仕組み |
| 6 | CDN の仕組みと役割 |
| 7 | WebSocket ― 双方向リアルタイム通信 |
| 8 | キャッシュ戦略(ブラウザ・サーバー・CDN) |
| 9 | CORS ― クロスオリジンの壁を理解する |
| 10 | REST API 設計の基本原則 |
「この記事が役に立った」と思ったら、LGTM とストックをお願いします。
@kotaro_ai_lab
AI活用や開発効率化について発信しています。フォローお気軽にどうぞ!




