OAuthをログイン連携で使う前に押さえる認可の基本
OAuthは、別サービスのIDとパスワードを自分のサイトに預けずに、必要な範囲だけアクセスを許可するための仕組みです。
たとえばWordPressサイトで「Googleアカウントでログイン」や、予約システムからGoogleカレンダーへ予定を書き込む連携を作るとき、利用者のパスワードを受け取るのではなく、許可された操作だけに使えるトークンを受け取ります。
最初に分けておきたいのはここです。OAuthの中心はログインそのものではなく、認可です。 「このアプリに、私のこのデータへのアクセスを許可する」というやり取りを安全に扱うための標準です。
この記事で分かることは次の通りです。
- OAuthで何ができるか
- ログイン連携と認可の違い
- アクセストークン、スコープ、リダイレクトURIの役割
- 実務でよく見る設定項目とつまずきやすい原因
- 最小限のリクエスト例と安全に扱うための注意点
対象は、Web制作、WordPress、サーバー運用、自動化で外部サービス連携を扱い始める人です。この記事では2026年7月時点のOAuth 2.0、OpenID Connect、PKCE、OAuth 2.0 Security Best Current Practiceの公開情報を前提にします。
OAuthは「パスワードを渡さずに許可を渡す」仕組み
OAuthを使う理由は、外部アプリにユーザーのパスワードを渡さず、必要な範囲と期間だけアクセスを許可できるようにするためです。
古い考え方では、外部ツールがユーザーの代わりに操作するには、そのユーザーのIDとパスワードを預かる必要がありました。これは危険です。外部ツールが侵害されれば、パスワードそのものが漏れます。ユーザーが一部の権限だけを止めたい場合も、結局パスワード変更のような大きな対応になりがちです。
OAuth 2.0の仕様であるRFC 6749は、この問題を「認可サーバー」と「アクセストークン」で分けます。
実務では、次のような場面で出てきます。
- WordPressプラグインからGoogle、Microsoft、X、GitHubなどのAPIを使う
- 自社管理画面に「Googleでログイン」を追加する
- ノーコードツールや自動化ツールに外部サービスへのアクセスを許可する
- サーバー側のバッチ処理で外部APIを呼び出す
- SaaS連携で「読み取りだけ」「投稿だけ」など権限を分ける
ここがポイント: OAuthは「あなたのパスワードをこのアプリに渡す」のではなく、「このアプリに、この範囲の操作だけ許可する」に置き換える仕組みです。
ログイン連携とOAuthは同じではない
「Googleでログイン」のような画面でOAuthが見えるため、OAuthをログインの規格だと思いやすいですが、実務ではここを分けて理解する必要があります。
OAuthは認可、つまり「アクセスを許可する」ための枠組みです。一方で、ログインで必要なのは「この利用者は誰か」を確認することです。この本人確認の層としてよく使われるのがOpenID Connectです。
OpenID Connect Core 1.0は、OAuth 2.0の上に本人確認のための情報を載せる仕組みです。ログイン連携でよく見るid_tokenは、OAuthだけではなくOpenID Connect側の考え方です。
実務での見分け方
外部サービス連携の設定画面では、似た言葉が並びます。迷ったら、目的で分けます。
- 外部APIを呼びたい: OAuthのアクセストークンを見る
- ユーザーをログインさせたい: OpenID ConnectのIDトークンやユーザー情報を見る
- 両方したい: OpenID Connectで本人確認し、必要に応じてOAuthのスコープでAPIアクセスも許可する
たとえば「Googleアカウントで管理画面にログイン」は本人確認が主目的です。一方、「Google Driveにファイルを保存する」はAPIアクセスの許可が主目的です。画面上は同じGoogleの同意画面に見えても、アプリ側で確認すべき値が違います。
登場人物は4つで考える
OAuthの流れは、4つの役割に分けると理解しやすくなります。
| 役割 | 実務での例 | 何をするか |
|---|---|---|
| リソースオーナー | サイト利用者、管理者 | 自分のデータへのアクセスを許可する |
| クライアント | WordPressプラグイン、自社Webアプリ、連携ツール | 許可を受けてAPIを呼び出す |
| 認可サーバー | Google、Microsoft、GitHubなどの認可基盤 | ログイン確認、同意画面、トークン発行を行う |
| リソースサーバー | Google Drive API、GitHub APIなど | アクセストークンを確認してデータを返す |
ここで大事なのは、クライアントがユーザーのパスワードを受け取らないことです。ユーザーは認可サーバー側でログインし、クライアントには許可の結果としてトークンが渡されます。
アクセストークンは合鍵に近い
アクセストークンは、APIに対して「この操作は許可済みです」と示す文字列です。合鍵に近いものですが、家の鍵そのものではありません。
多くの場合、アクセストークンには次のような制約があります。
- 有効期限がある
- 許可されたスコープだけに使える
- 対象APIやサービスが決まっている
- 取り消しや再発行の対象になる
この性質があるため、万一漏えいしてもパスワード漏えいより被害を小さく抑えやすくなります。ただし、トークンも認証情報です。ログ、フロントエンドコード、公開リポジトリに出してはいけません。
基本フローは「認可コード」を経由する
Webアプリでまず押さえるべき基本は、認可コードフローです。現在の実装では、特にブラウザやモバイルアプリを含む多くの場面でPKCEも重要になります。
RFC 7636で定義されたPKCEは、認可コードを横取りされてもトークン交換に使いにくくするための仕組みです。さらに、OAuth 2.0 Security Best Current PracticeやOAuth 2.1の整理では、古いImplicitフローやパスワードを直接渡す方式を避ける方向が明確です。
典型的な流れ
実務で見る流れは、おおむね次の順番です。
- アプリが認可URLへユーザーを移動させる
- ユーザーが認可サーバーでログインする
- 同意画面で許可するスコープを確認する
- 認可サーバーがアプリのリダイレクトURIへ戻す
- アプリが
codeを受け取る - サーバー側で
codeをアクセストークンに交換する - アクセストークンを使ってAPIを呼び出す
この流れの途中でよく出る設定項目が、client_id、client_secret、redirect_uri、scope、stateです。
client_id: アプリを識別するIDclient_secret: サーバー側アプリで使う秘密情報redirect_uri: 認可後に戻ってくるURLscope: 許可してほしい操作範囲state: CSRF対策や戻り先管理に使うランダム値
client_secretは名前の通り秘密情報です。GoogleのOAuth 2.0ドキュメントでも、client_secret.jsonを公開場所やソースツリーに置かないよう注意されています。
最小のリクエスト例で流れを見る
ここでは特定サービスに依存しない形で、OAuthのリクエストがどのような構造になるかを見ます。実際のURL、スコープ、パラメータ名の細部はサービスごとの公式ドキュメントに従ってください。
入力例: 認可URLを作る
ユーザーを認可サーバーへ送るURLは、次のような形になります。
https://auth.example.com/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&scope=profile%20email&state=RANDOM_STATE
このURLをブラウザで開くと、ユーザーは認可サーバー側でログインし、同意画面を確認します。許可されると、アプリのredirect_uriへ戻ります。
出力例: コールバックでcodeを受け取る
認可後、アプリ側には次のようなURLで戻ってきます。
https://example.com/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATE
ここでアプリは、最初に発行したstateと戻ってきたstateが一致するかを確認します。一致しない場合、別のサイトから差し込まれたリクエストの可能性があるため処理を止めます。
コード交換: curlでトークンを取得する形
サーバー側では、受け取ったcodeをトークンエンドポイントに送ります。
curl -X POST https://auth.example.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=https://example.com/callback" \
-d "client_id=CLIENT_ID" \
-d "client_secret=CLIENT_SECRET"
成功すると、次のようなJSONが返ります。
{
"access_token": "ACCESS_TOKEN",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "REFRESH_TOKEN",
"scope": "profile email"
}
access_tokenをAPI呼び出しに使います。Bearerトークンは、一般にHTTPヘッダーへ入れます。
curl https://api.example.com/v1/me \
-H "Authorization: Bearer ACCESS_TOKEN"
この例で重要なのは、アクセストークンをURLのクエリ文字列に入れないことです。URLはアクセスログ、ブラウザ履歴、プロキシログに残りやすいためです。
WordPressやWeb制作でよくある設定ポイント
OAuth連携の失敗は、コードの前に設定で起きることが多いです。特にWordPressや小規模なWebアプリでは、管理画面で入力する値と実際のURLが少しずれているだけでエラーになります。
リダイレクトURIは完全一致で見る
OAuth 2.1の整理でも、リダイレクトURIは厳密な一致が重視されています。実務では次の違いで失敗します。
http://とhttps://が違う- 末尾の
/がある、ない wwwあり、なしが違う- 本番URLとステージングURLを取り違えている
- WordPressの管理URLやREST APIのURLを誤って登録している
たとえば、サービス側に登録したURLが次の場合を考えます。
https://example.com/oauth/callback
実際に戻ってきたURLが次なら、別のURLとして扱われる可能性があります。
https://example.com/oauth/callback/
最後のスラッシュだけでも一致しないことがあります。OAuth設定画面では、プラグインやアプリが表示するコールバックURLをそのままコピーするのが基本です。
スコープは広げすぎない
スコープは「何を許可するか」を表す文字列です。read、write、profile、emailのようにサービスごとに定義されます。
便利だからといって最初から広いスコープを要求すると、ユーザーの同意画面で不信感を持たれやすくなります。Googleのドキュメントでも、必要なリソースだけを要求する考え方が説明されています。
実務では、次のように分けて考えると判断しやすくなります。
- ログインだけ: プロフィール確認に必要な最小スコープ
- 一覧表示だけ: 読み取りスコープ
- 投稿や更新: 書き込みスコープ
- バックグラウンド処理: リフレッシュトークンの要否も確認
「あとで使うかもしれない」権限を先に取るより、必要になったタイミングで追加許可を求めるほうが、利用者にも説明しやすくなります。
よくある失敗と直し方
OAuthのエラーは英語の短いコードで返ることが多く、原因が分かりにくいものです。まずはエラー名と設定項目を対応させて見ます。
| エラーや症状 | よくある原因 | 確認する場所 |
|---|---|---|
redirect_uri_mismatch | 登録URLと実際の戻り先URLが違う | 認可サービスのアプリ設定、WordPress側のコールバックURL |
invalid_client | client_idまたはclient_secretが違う | 環境変数、設定ファイル、管理画面の入力値 |
invalid_grant | 認可コードの期限切れ、二重使用、redirect_uri不一致 | コールバック処理、トークン交換処理 |
| 同意画面で警告が出る | 未確認アプリ、広いスコープ、公開前設定の不足 | 提供元の開発者コンソール、アプリ審査設定 |
| API呼び出しが401になる | アクセストークン期限切れ、スコープ不足 | トークン保存処理、スコープ、リフレッシュ処理 |
NG例: トークンをログに出す
デバッグ中にやりがちな失敗が、レスポンスJSONをそのままログへ出すことです。
console.log(tokenResponse);
開発環境では便利に見えますが、access_tokenやrefresh_tokenがログ基盤、チャット通知、エラー監視ツールに流れる危険があります。
改善するなら、値そのものではなく、必要な状態だけを記録します。
console.log({
token_type: tokenResponse.token_type,
expires_in: tokenResponse.expires_in,
scope: tokenResponse.scope
});
トークンの全文、client secret、認可コードはログに残さない。これは小さなルールですが、事故を防ぐ効果は大きいです。
APIキー、OAuth、OpenID Connectの使い分け
外部連携では、OAuth以外にもAPIキーやOpenID Connectが出てきます。どれが常に上という話ではなく、目的が違います。
| 方式 | 主な目的 | 向いている場面 | 注意点 |
|---|---|---|---|
| APIキー | アプリやプロジェクトの識別 | サーバー間の単純なAPI利用、公開データ取得 | ユーザーごとの同意や細かい権限管理には向かないことがある |
| OAuth | ユーザーやアプリによるアクセス許可 | 外部サービスのデータを読み書きする連携 | リダイレクトURI、スコープ、トークン管理が必要 |
| OpenID Connect | ユーザー本人確認 | GoogleやMicrosoftアカウントでログインする機能 | IDトークンの検証を正しく行う必要がある |
WordPressで考えるなら、APIキーは「このサイトから外部APIを使うための鍵」、OAuthは「このユーザーが外部サービスのデータ利用を許可した証」、OpenID Connectは「このユーザーが誰かを確認する仕組み」と見ると整理しやすくなります。
実装前のチェックリスト
OAuth連携を作る前に、次の項目を先に決めておくと手戻りが減ります。
- 目的はログインか、APIアクセスか、両方か
- 認可サーバーとAPI提供元はどこか
- 必要なスコープは最小限に絞れているか
- 本番、検証、ローカルのリダイレクトURIを分けて登録したか
- client secretを公開ディレクトリやGit管理下に置いていないか
- アクセストークンとリフレッシュトークンの保存場所を決めたか
- トークンをログに出さない設計になっているか
- エラー時にユーザーへ見せる文言と、管理者向けログを分けているか
初心者が最初につまずくのは、OAuthの理論そのものよりも「ログインなのか、認可なのか」「どのURLを登録するのか」「どのスコープが必要なのか」の3点です。ここを先に紙に書ける状態にすると、設定画面で迷いにくくなります。
今後見るべきポイント
OAuthまわりは、古いサンプルコードが検索結果に残りやすい領域です。特にresponse_type=tokenを使うImplicitフローや、ユーザーのパスワードをアプリが直接受け取る方式は、新しい実装では避ける前提で確認したほうが安全です。
これから実装するなら、次の順で見ると判断しやすくなります。
- Webアプリでは認可コードフローを基本にする
- ブラウザ、モバイル、公開クライアントではPKCEを確認する
- ログイン用途ならOpenID Connectの仕様や提供元ドキュメントを見る
- トークンはURLではなくAuthorizationヘッダーで送る
- リダイレクトURIとスコープを設定画面で毎回確認する
OAuthは一度理解すると、外部サービス連携の画面で見える項目の意味がつながります。次にOAuth設定で詰まったら、まず「誰が、どのアプリに、どのデータへの、どの範囲のアクセスを許可しているのか」を書き出すところから始めると、エラーの原因を絞り込みやすくなります。
