1 学ぶ理由
・チーム開発でOAuthの外部連携のタスクをアサインしてもらったから。
・バックエンドエンジニアとして、今回はしっかりセキュアなものを作らねばならないから。
この記事で書くこと
- OAuthの概要
- 今後の実装で理解を深めたいことの整理
OAuthの概要
そもそもOAuthとは何かという話からなのだが、
OAuthの定義: パスワードを渡さずに**「アクセス権限」を委譲**するためのプロトコルである、ということになっている。
つまり、「認証」と「認可」としての「認可」プロトコルだということ!
(Oがプロトコルらしい)
認証 (Authentication): 「あなたは誰ですか?」
〇認可 (Authorization): 「あなたはこれをする権限がありますか?」
ここをさらに全体像としては
| 名称 | 役割 | 補足・よくある使われ方 | |
|---|---|---|---|
| ① | 認証 (Authentication) | 「この人は誰か?」を確認する | 例:ID・パスワード、指紋、2FAなど |
| ② | OAuth 2.0 | 「何を許可するか?」=認可(Authorization) | GoogleやGitHubのAPI連携など |
| ③ | OpenID Connect (OIDC) | OAuthの上に「認証の仕組み」を追加したもの | 「Googleでログイン」などに使われる |
| ④ | JWT (JSON Web Token) | トークン(鍵)の形式。OAuth/OIDCでよく使われる | トークンを使って認証状態を保持する |
であるとのこと。ゆえに一連の通りシステムでの外部連携などの際には、それぞれが関連し合っていなくてはならないことがわかる。
OAuthでの登場人物について
公式ドキュメントより、
| アクター名 | 役割・立場 | 具体的な例 | 主な責務(何をする人か) |
|---|---|---|---|
| 🧑💻 Resource Owner(リソースオーナー) | 自分のデータの持ち主(=ユーザー本人) | あなた(Googleアカウントの持ち主) | - 自分のデータを他のアプリに共有してよいか「同意」する - OAuthフローを開始する(ログイン・認可操作) |
| 💼 Client(クライアントアプリ) | 外部サービスにアクセスしたいアプリ | あなたが開発しているWebアプリ / モバイルアプリ | - Resource Ownerの代わりにデータを取得したい - Authorization Serverを通じてトークンをもらう |
| 🔐 Authorization Server(認可サーバー) | アクセス許可やトークンを発行する公式サーバー | GoogleのOAuthサーバー(accounts.google.com) |
- ユーザー認証を行う(OIDCの場合) - 同意画面を表示して認可を処理 - アクセストークン/IDトークンを発行する |
| 🗄️ Resource Server(リソースサーバー) | 実際のデータを保管しているAPIサーバー | Google API(www.googleapis.com) |
- アクセストークンを検証してアクセスを許可/拒否 - 許可された範囲内のデータを返す |
となる。これらは立場から考えると、
| 観点 | Resource Owner | Client | Authorization Server | Resource Server |
|---|---|---|---|---|
| 目的 | 自分のデータを安全に共有したい | ユーザーのデータにアクセスしたい | アクセス権を安全に発行したい | データを安全に提供したい |
| 信頼関係 | Authorization Serverを信頼している | Authorization Serverに登録されている | Resource Ownerを認証する | Authorization Serverから発行されたトークンを信頼 |
| トークンとの関係 | トークンの発行に同意 | トークンを受け取り利用 | トークンを発行 | トークンを検証しデータを返す |
これらの設定が必要になるのだ。
具体例で考える
リクエスト
curl -X POST https://oauth2.googleapis.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "code=4/0Ad9I..." \
-d "client_id=1234567890-abcdefg.apps.googleusercontent.com" \
-d "client_secret=GOCSPX-xyz..." \
-d "redirect_uri=https://yourapp.com/oauth2callback" \
-d "grant_type=authorization_code"
- code:googleから返された認可コード
- client_id/client_secret:アプリのクレデンシャル
- redirect_uri:google開発者コンソールで登録されたURLと一致
- grant_type:標準的なOAuth認可コードフロー
レスポンス
{
"access_token": "ya29.a0AfH6SMCQk...",
"expires_in": 3599,
"refresh_token": "1//0gA5abcdEf...",
"scope": "openid email profile https://www.googleapis.com/auth/drive.readonly",
"token_type": "Bearer",
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ij..."
}
id_tokenがある⇒OpenIDConnect対応
今後の深堀について
①フローの使い分け・把握
| フロー名 | 主な用途 | 特徴 | 備考 |
|---|---|---|---|
| Authorization Code Flow | サーバーサイドWebアプリ | 最も安全。認可コード→アクセストークン交換の2段階構成 | PKCEを使うことでSPAでも利用可能 |
| Implicit Flow | 旧来のSPA向け(推奨されない) | アクセストークンが直接ブラウザに返るため安全性が低い | 現在は非推奨 |
| Client Credentials Flow | バックエンド間通信 | ユーザーの同意不要。アプリ自身の資格情報で認可される | サービス間APIで利用 |
| Password Flow | レガシー用途 | ID/PWを直接送る。OAuthの思想に反する | 原則非推奨 |
② トークンの使いわけ
| トークン名 | 役割 | 使用場所 | 有効期限 | 補足 |
|---|---|---|---|---|
| Access Token | APIアクセス用のキー | Resource Server | 数分〜1時間程度 | スコープに基づいてアクセス可能 |
| Refresh Token | アクセストークン再発行用 | クライアント(安全に保管) | 長期間(数日〜数週間) | サーバーサイドでのみ使用が望ましい |
| ID Token | 認証情報(ユーザー情報)を表す | クライアント(OIDCのみ) | Access Tokenと同等 | JWT形式(署名付き) |
OpenIdConnectのid_tokenに基づく sub(subjekt・ユーザー識別子)やemailなどが含まれていること
③ セキュリティ設計
OAuthを正しく使わないと、トークンの漏えいやなりすまし攻撃につながる。以下を常に意識したいと思う。
-
redirect_uri は必ずホワイトリストで制限する
-
client_secret はクライアント(ブラウザ)で扱わない(サーバー保管)
-
SPAではPKCE(Proof Key for Code Exchange)を必ず利用する
⇒ -
HTTPS通信を前提とする(トークンが平文で流れないように)
-
トークンを保存する場合は セキュアクッキー or サーバーセッション を利用する
⇒xssやcsrf対策