Google OAuthのredirect_uri_mismatchを直す|登録URIと実際のcallbackを照合

Google Web server OAuthのredirect_uriを、実際の認可要求、client_id、登録callbackの三点で照合します。

AIものさし編集部

Google OAuthのredirect_uri_mismatchは、認可要求で送ったredirect_uriが、そのclient_idに登録されたAuthorized redirect URIsと一致しない場合に発生します。登録画面だけを見てURIを追加し続ける前に、実際の要求と対象clientを一組で確認します。

ここではWebサーバーアプリのOAuthを扱います。DesktopアプリやCLIのloopback redirectには別の仕様があるため、本稿のWeb clientの比較をそのまま適用しません。以下のURLは説明用の架空例で、実サービスでのログイン試験結果ではありません。

三つの値を同じログイン試行から集める

比べるのは、認可要求のclient_id、送信されたredirect_uri、そのclientに登録されたredirect URIです。別のGoogle Cloud projectや、同名の開発用clientを開くと、正しいURIが見えていても比較対象が違います。

表は横にスクロールできます

項目確認場所取り違えやすい値
送信clientauthorize要求のclient_id管理画面で最後に開いたclient
送信callback同じ要求のredirect_uriログイン開始ページのURL
登録callback送信clientに対応する設定別環境の登録URI

認可コードやstate、Cookie、tokenを含むブラウザのURL全体をチケットへ貼りません。必要なパラメータだけを扱い、調査担当者が閲覧できる経路へ最小限を記録します。redirect_uriを読む際はURLエンコードされたパラメータ値を解釈し、エンコード文字列の見た目だけで別物と判断しないようにします。

認可要求に含めたredirect_uriの値そのものを比較し、元から含まれるqueryは保持します。認可後に追加されたcodeやstateを登録URIに足しません。callbackへ戻った後の完成済みURLを、そのまま登録欄へコピーしないようにします。

完全一致の比較表で差分を見つける

GoogleのWebサーバー OAuthの仕様(新しいタブで開く)は、指定clientの登録URIとの完全一致を要求し、scheme・大文字小文字・末尾slashも一致させるよう説明しています。似て見えることや、ブラウザで同じ画面へ転送されることを一致の代わりにしません。

表は横にスクロールできます

部分登録値の架空例送信値の架空例調べる差分
schemehttpshttp外部公開URLの生成元
hostapp.example.compreview.example.com環境の選択
path/oauth/callback/auth/callbackcallbackルート
末尾slash/oauth/callback/oauth/callback/URI生成と登録

この表は比較の方法であり、すべてのアプリで表のURIを登録する指示ではありません。portやqueryを含め、実際に設定したURI全体を確認します。不要なredirect先を大量に登録してエラーを隠さないようにします。

たとえば登録がhttps://app.example.com/oauth/callbackで、送信値がhttps://preview.example.com/oauth/callbackなら、まずその試行が本番へ入るべきだったのか、preview環境へ入るべきだったのかを決めます。本番設定を開いたままpreviewのURLを追加する判断には進みません。

アプリが誤ったcallbackを生成していないかを見る

reverse proxyや負荷分散装置の背後では、外部からはHTTPSでもアプリが内部のHTTPや内部hostを見てURLを組み立てる構成があります。これは今回の原因と決まったわけではありません。実際の送信URIに内部hostや意図しないschemeが含まれる場合の調査先です。

表は横にスクロールできます

観測した差分アプリ側の確認先登録を変える前の判断
内部hostを送っている公開base URL・proxy設定外部向けURI生成を直すか
古いpreview domainデプロイ設定・設定の読込時点古い設定が残る実行環境はどこか
正しいURIだが別clientclient設定の環境分離clientと登録先を揃える
正しいclientに正しいURIが未登録clientのredirect設定所有・用途を確認して登録するか

転送headerを無条件に信頼する設定変更は避け、利用frameworkの公式手順と信頼するproxyの範囲に従います。エラーを直すために任意のHost headerからcallbackを生成する設計へ変える必要はありません。

JavaScript originとredirect URIを混同しない

画面の出発点のoriginと、認可処理が戻るcallbackは用途が違います。origin欄にドメインが登録されていても、Webサーバー OAuthのcallbackがAuthorized redirect URIsに登録されたことにはなりません。利用している認証フローを確認し、該当するclient設定の項目を比較します。

アプリのライブラリがcallbackルートを提供している場合は、推測したパスではなく、そのライブラリの設定と実際の認可要求を確認します。環境変数を直しただけで稼働中のプロセスへ反映されたとみなさず、最新の試行で送信値を取り直します。

修正後は新しい認可要求を一回ずつ照合する

  1. 正しい環境・client・callbackの組合せを確定する。
  2. 誤りがアプリの生成値か登録側の不足かを分け、必要な側だけを変更する。
  3. 新しいログイン試行を開始し、実際の送信URIが意図した値かを再確認する。
  4. callbackへ戻った後の処理も確認する。別エラーなら新しい段階の問題として記録する。

callback不一致が解消しても、認可コードの交換、ユーザー同意、scope、APIのresource権限まで成功したとは限りません。別の段階で失敗したら、URIを再び追加するのではなく、観測した新しいエラーへ切り替えます。refresh tokenを保存した後のinvalid_grantは、この認可入口とは分けて調べます。

確認した公式資料