OAuth 2.0 — 第三者認証の原理
このトピックを終えると
OAuth 2.0が解決する問題、Authorization Code Flow の全体の流れ、そして Access Token と Refresh Token の役割を理解できるようになります。
なぜパスワードを受け取らないのか
「Google でログイン」、または「Kakao でログイン」ボタンをクリックすると、ユーザーは自分のサービスにパスワードを入力しません。Google の画面に移動して Google にログインし、その後、元の画面に戻ってきます。
なぜこのような複雑な仕組みになっているのでしょうか?それは簡単です — パスワードを他人のサーバーに渡すべきではないからです。
もしあるサービスが「Google アカウントのメールアドレスとパスワードを入力してください」と言う場合、そのサービスは自分のパスワードを保存できることになります。もしそれが漏洩した場合、Google アカウント全体が危険にさらされる可能性があります。OAuth はこの問題を解決します — パスワードの代わりに「許可証」を与えるのです。
4 人の登場人物
OAuth には 4 つの役割があります。
| 役割 | 意味 | 例 |
|---|---|---|
| Resource Owner | ユーザー(データの所有者) | あなた |
| Client | 私たちが作成したサービス | 私たちのウェブアプリ |
| Authorization Server | 認証を担当するサーバー | Google 認証サーバー |
| Resource Server | ユーザーデータがあるサーバー | Google プロファイル API |
名前が直感的ではありません。「Client」はユーザーではなく、私たちのサーバーであるという点に注意してください。OAuth の観点から見ると、私たちのサービスは Google に「データをお願いします」とリクエストする立場なので、Client となります。
Authorization Code Flow
最も一般的に使用されるフローです。ステップごとに見ていきましょう。
1. ユーザーが「Google でログイン」をクリック
2. 私たちのサーバーが Google 認証サーバーにリダイレクト
→ URL に client_id、redirect_uri、scope を含める
3. ユーザーが Google でログインし、「このアプリに許可」をクリック
4. Google が redirect_uri に「認可コード (code)」を送信
5. 私たちのサーバーが認可コードと client_secret を使用して Google にリクエスト
6. Google が Access Token を発行
7. 私たちのサーバーが Access Token を使用してユーザー情報をリクエスト重要なのは、2 回交換するということです。まず、認可コード(使い捨て)を受け取り、それを使って実際のトークンを受け取ります。なぜ一度にトークンを発行しないのでしょうか?
4 段階で認可コードは URL パラメーターで送信されます。URL はブラウザの履歴に残し、ログにも記録されます。もしここにトークンが含まれていると、誰かがそれを見ることができます。認可コードは使い捨てであり、短時間で期限切れになるため、漏洩しても被害が限定されます。
5 段階で実際のトークン交換は、サーバー間の通信(バックチャネル)で行われます。client_secret が含まれており、これは決してブラウザに公開されることはありません。
Access Token と Refresh Token
// Google が応答するトークンの構造(例)
{
"access_token": "ya29.a0AfH6SM...",
"expires_in": 3600, // 1 時間
"refresh_token": "1//0eXyz...",
"token_type": "Bearer",
"scope": "email profile"
}| トークン | 寿命 | 用途 |
|---|---|---|
| Access Token | 短い(通常 1 時間) | API 呼び出しに使用 |
| Refresh Token | 長い(数週間〜数ヶ月) | Access Token の再発行に使用 |
Access Token が期限切れになると、Refresh Token を使用して新しい Access Token を取得します。毎回ユーザーに「再度ログインしてください」と言う必要はありません。
なぜ Access Token を長くしないのでしょうか?トークンが漏洩した場合の被害期間を最小限に抑えるためです。1 時間のトークンが漏洩した場合、1 時間だけ危険ですが、1 年のトークンが漏洩した場合、1 年間危険です。
scope — 権限の範囲
https://accounts.google.com/o/oauth2/v2/auth?
client_id=OUR_CLIENT_ID&
redirect_uri=http://localhost:3000/callback&
scope=email+profile&
response_type=codescope は、どこまでアクセスできるかを定義するものです。email profile の場合、メールアドレスとプロフィール写真だけを取得でき、Google ドライブのファイルは参照できません。
ユーザーが「このアプリに許可」をクリックしたときに表示される画面に「このアプリはあなたのメールアドレスにアクセスします」と表示されるのが scope です。
最小権限の原則 — 必要なものだけをリクエストしてください。「すべての権限」をリクエストすると、ユーザーは警戒して拒否する可能性があります。
私たちのサービスで実装する場合
実際の実装で知っておくべきこと:
- プロバイダー登録: Google/Kakao の開発者コンソールでアプリを登録し、
client_idとclient_secretを取得します。 - redirect_uri の設定: 認可コードを受け取るコールバック URL を登録します。登録されていない URL にはリダイレクトされません。
- 状態値 (state) の検証: CSRF 対策用のランダムな文字列をリクエストに含め、コールバックで一致するかどうかを確認します。
// Express でのコールバック処理(概念)
app.get('/callback', async (req, res) => {
const { code, state } = req.query;
// 1. state 検証(CSRF 対策)
if (state !== req.session.oauthState) {
return res.status(403).send('Invalid state');
}
// 2. 認可コードでトークン交換(サーバー → Google、バックチャネル)
const tokenRes = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
body: new URLSearchParams({
code,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
grant_type: 'authorization_code',
}),
});
const { access_token } = await tokenRes.json();
// 3. Access Token でユーザー情報をリクエスト
const userRes = await fetch(
'https://www.googleapis.com/oauth2/v2/userinfo',
{ headers: { Authorization: `Bearer ${access_token}` } }
);
const user = await userRes.json();
// 4. セッションにユーザーを保存
req.session.user = user;
res.redirect('/');
});核心
OAuth 2.0 は、パスワードの代わりにトークンを使用して権限を委任するプロトコルです。 Authorization Code Flow は、認可コード(使い捨て)→ Access Token(短期)→ API 呼び出しの 2 段階の交換です。 Access Token は短く、Refresh Token で更新 — 漏洩時の被害を最小限に抑える設計です。
→ 次のトピックで、Passport.js + Google OAuth を実際に実装します。