#はじめに
「Googleでログイン」「GitHubで続ける」——これらのボタンを押したとき、裏側では何が起きているのでしょうか?
OAuth 2.0とOIDC(OpenID Connect)は、このような「ソーシャルログイン」や「API連携」を実現するための標準仕様です。これらを理解することで、セキュアな認証・認可システムを設計できるようになります。
この記事を読むと、以下のことができるようになります:
- 認証と認可の違いを理解できる
- OAuth 2.0の基本的なフローがわかる
- OIDCがOAuth 2.0に何を追加するのかがわかる
- 実装時のセキュリティ上の注意点を理解できる
#認証と認可の違い
OAuth 2.0とOIDCを理解するには、まず「認証」と「認可」の違いを明確にする必要があります。
#認証(Authentication)
「あなたは誰ですか?」 を確認すること。
ユーザー: 「私は山田です」
システム: 「パスワードを入力してください」
ユーザー: 「****」
システム: 「確かに山田さんですね」 ← 認証完了
#認可(Authorization)
「あなたは何ができますか?」 を確認すること。
山田さん: 「Googleドライブのファイルにアクセスしたい」
Google: 「このアプリにファイルへのアクセスを許可しますか?」
山田さん: 「許可する」
Google: 「アクセス権を与えます」 ← 認可完了
#重要なポイント
| 認証 | 認可 | |
|---|---|---|
| 質問 | Who are you? | What can you do? |
| 結果 | 身元の確認 | 権限の付与 |
| 例 | ログイン | APIアクセス許可 |
OAuth 2.0は認可の仕様であり、認証の仕様ではありません。これは非常に重要な違いです。
#OAuth 2.0とは
OAuth 2.0は、サードパーティアプリケーションにリソースへのアクセス権を安全に委譲するための認可フレームワークです。
#なぜ必要か
従来の方法では、サードパーティアプリにパスワードを渡す必要がありました。
# 危険な従来の方法
「このアプリにGoogleのユーザー名とパスワードを入力してください」
問題:
- パスワードが漏洩するリスク
- アプリに全権限が渡る
- パスワード変更時に再設定が必要
OAuth 2.0では、パスワードを渡さずに、必要な権限だけを委譲できます。
# OAuth 2.0の方法
「Googleにリダイレクトして、このアプリにカレンダーへのアクセスを許可してください」
メリット:
- パスワードを共有しない
- 必要な権限だけを付与
- いつでも取り消し可能
#OAuth 2.0の登場人物
| 役割 | 説明 | 例 |
|---|---|---|
| リソースオーナー | リソースの所有者(ユーザー) | あなた |
| クライアント | リソースにアクセスしたいアプリ | カレンダーアプリ |
| 認可サーバー | アクセス権を発行するサーバー | Googleの認可エンドポイント |
| リソースサーバー | 保護されたリソースを持つサーバー | Google Calendar API |
#認可コードフロー
最もセキュアで一般的なフローです。Webアプリケーションで推奨されます。
[ユーザー] [クライアントアプリ] [認可サーバー] [リソースサーバー]
| | | |
|-- 1. ログインボタン -->| | |
| | | |
|<-- 2. 認可サーバーへリダイレクト --------| |
| | | |
|------------------ 3. 認可リクエスト ---->| |
| | | |
|<----------------- 4. ログイン画面 ------| |
| | | |
|------------------ 5. 認証情報入力 ----->| |
| | | |
|<----------------- 6. 権限確認画面 ------| |
| | | |
|------------------ 7. 許可する ---------->| |
| | | |
|<-- 8. 認可コード付きでリダイレクト ------| |
| | | |
| |-- 9. 認可コード + クライアントシークレット -->|
| | | |
| |<-- 10. アクセストークン --| |
| | | |
| |------------------- 11. API呼び出し ------->|
| | | |
| |<------------------- 12. リソース ----------|
| | | |
|<-- 13. 結果表示 --| | |
#各ステップの詳細
#2-3. 認可リクエスト
GET https://accounts.google.com/o/oauth2/v2/auth
?client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourapp.com/callback
&response_type=code
&scope=https://www.googleapis.com/auth/calendar.readonly
&state=xyz123
| パラメータ | 説明 |
|---|---|
client_id | アプリの識別子 |
redirect_uri | 認可後のリダイレクト先 |
response_type | code(認可コードフロー) |
scope | 要求する権限 |
state | CSRF対策用のランダム値 |
#8. 認可コードの受け取り
GET https://yourapp.com/callback
?code=AUTHORIZATION_CODE
&state=xyz123
stateの検証を必ず行ってください。 リクエスト時に送ったstateと一致しなければ、CSRF攻撃の可能性があります。
#9-10. トークンの取得
POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=https://yourapp.com/callback
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
レスポンス:
{
"access_token": "ya29.a0AfH6...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "1//0g..."
}
#PKCE(Proof Key for Code Exchange)
SPAやモバイルアプリなど、クライアントシークレットを安全に保管できない環境では、PKCEを使用します。
#PKCEの仕組み
- クライアントがランダムな
code_verifierを生成 code_verifierのハッシュ値(code_challenge)を認可リクエストに含める- トークン取得時に
code_verifierを送信 - 認可サーバーがハッシュを検証
# 認可リクエスト
code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
# トークンリクエスト
code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
これにより、認可コードを傍受されても、code_verifierがなければトークンを取得できません。
#OpenID Connect(OIDC)
OIDCは、OAuth 2.0の上に認証機能を追加した仕様です。
OAuth 2.0だけでは「誰がログインしたか」はわかりません(認可のみ)。OIDCはIDトークンを導入し、ユーザーの身元情報を取得できるようにします。
#OIDCが追加するもの
| 要素 | 説明 |
|---|---|
| IDトークン | ユーザー情報を含むJWT |
| UserInfoエンドポイント | ユーザー情報を取得するAPI |
| 標準スコープ | openid, profile, emailなど |
#IDトークンの例
{
"iss": "https://accounts.google.com",
"sub": "110169484474386276334",
"aud": "YOUR_CLIENT_ID",
"exp": 1311281970,
"iat": 1311280970,
"name": "山田太郎",
"email": "yamada@gmail.com",
"picture": "https://..."
}
#OIDCフロー
OAuth 2.0のフローとほぼ同じですが、scopeにopenidを含め、レスポンスにid_tokenが追加されます。
# 認可リクエスト
scope=openid profile email
# トークンレスポンス
{
"access_token": "ya29.a0AfH6...",
"id_token": "eyJhbGciOiJSUzI1...", ← これが追加
"token_type": "Bearer",
"expires_in": 3600
}
#セキュリティ上の注意点
#1. stateパラメータの使用
CSRF攻撃を防ぐため、必ずstateパラメータを使用し、コールバック時に検証してください。
// 認可リクエスト前
const state = generateRandomString();
sessionStorage.setItem('oauth_state', state);
// コールバック時
const returnedState = new URLSearchParams(window.location.search).get('state');
if (returnedState !== sessionStorage.getItem('oauth_state')) {
throw new Error('Invalid state parameter');
}
#2. redirect_uriの厳密な検証
認可サーバー側で、登録されたredirect_uriと完全一致するか検証してください。
# 攻撃例
redirect_uri=https://yourapp.com/callback/../../../evil.com
# 対策: 完全一致のみ許可
#3. PKCEの使用
SPAやモバイルアプリでは、必ずPKCEを使用してください。
#4. トークンの安全な保管
- アクセストークン: メモリまたは短命Cookie
- リフレッシュトークン: HttpOnly Cookie
- IDトークン: 検証後、必要な情報のみ保持
#5. IDトークンの検証
IDトークンを受け取ったら、以下を検証してください:
- 署名の検証
iss(発行者)が期待値と一致aud(対象者)が自分のclient_idと一致exp(有効期限)が現在時刻より後
#まとめ
- 認証は「誰か」、認可は「何ができるか」
- OAuth 2.0は認可の仕様、OIDCが認証を追加
- 認可コードフローが最も安全、SPAではPKCEを併用
- IDトークンでユーザー情報を取得(OIDC)
- セキュリティ対策: state、PKCE、redirect_uri検証、トークン検証
#次のステップ
Cookie・認証・セッションモジュールはこれで完了です。Cookieの基本から、SameSite属性、セッション管理、JWT、そしてOAuth 2.0/OIDCまで学びました。
次のモジュールでは、オリジンとセキュリティについて学びます。同一オリジンポリシー、CORS、CSPなど、ブラウザのセキュリティモデルを理解しましょう。