Google OAuthのrefresh tokenがinvalid_grantになったとき、原因を分けて再認証する

Google OAuthのrefresh token更新失敗を、Testing条件、失効、client対応、組織のsession条件に分けて確認します。

AIものさし編集部

Google API連携が一度は動き、その後のrefresh処理でinvalid_grantになったら、同じtokenを再送し続ける前に「どの認証段階が失敗したか」を固定します。認可コードの交換失敗と、保存済みrefresh tokenによる更新失敗は、同じエラー名でも調べる対象が違います。

この記事は、ユーザーが同意して発行されたrefresh tokenを保存する連携の復旧手順です。service accountの署名や、認可画面へ入る前のcallback不一致は対象外です。以下の記録例は架空であり、実アカウントで復旧を実測した結果ではありません。

まずrefresh要求の失敗かを確認する

アプリのログで、token endpointへの要求がrefresh処理なのかを確認します。tokenそのものやclient secretを出力せず、要求種別、実行環境、時刻、エラー種別、設定の参照元を記録します。ライブラリが自動更新する場合も、最終APIの401だけでrefresh失敗と決めつけません。

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

観測した状態最初に調べる対象この時点で行わないこと
認可画面でcallbackのエラーOAuth clientとredirect URIrefresh tokenの削除
認可コード交換で失敗コード交換の要求内容Testing期間だけを原因と断定
保存済みtokenのrefreshが失敗発行時のclient・同意・失効条件無限再試行
refresh成功後にAPIが拒否scope・対象API・resource権限再認証だけで全権限を拡大

ユーザー全員が同時に失敗したか、一人だけか、環境を切り替えてからかも分けます。この観測は原因を断定する証拠ではなく、設定変更とユーザー単位の失効のどちらを先に調べるかを決める材料です。

Testingの7日条件は例外も含めて照合する

Googleのrefresh token expirationの説明(新しいタブで開く)では、ExternalかつPublishing statusがTestingのアプリで発行されるrefresh tokenには7日の期限があります。ただし要求scopeが名前・メール・プロフィールに関するuserinfo.email、userinfo.profile、openidまたは対応するOpenID Connect scopeの範囲だけの場合は例外です。

「約1週間で止まった」だけでは条件の成立を証明できません。発行時の公開状態と実際の要求scopeを確認し、現在の画面設定だけで過去のtokenを説明しないようにします。Productionへの切替を障害回避のためだけに行わず、公開・検証要件は別途判断します。

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

記録項目架空の確認例判断できること
token発行時のアプリ状態External / Testing7日条件を調べる対象か
要求したscopeの種類ファイル読取を含む基本プロフィールだけの例外か
最後にrefresh成功した時刻月曜の定期処理失敗までの観測区間
最初の失敗時刻翌週の定期処理発行日時の代用にはならない

たとえば週1回の処理なら、最後の成功と最初の失敗の間に数日あります。最初の失敗時刻をtokenが無効になった瞬間とみなすと、7日条件の検証を誤ります。発行記録が残っていない項目は不明のままにします。

失効とclientの取り違えを別々に調べる

公式資料は、ユーザーによるアクセス取消、長期間の未使用、Gmail scopeを含む場合のパスワード変更、発行数上限など、refresh tokenが使えなくなる複数の理由を挙げています。どれも今回必ず起きたという意味ではありません。アカウント管理者・利用者の変更記録と照合します。

並行して、tokenを発行したOAuth clientと、現在の更新処理が使うclientの対応を確認します。開発用と本番用の設定をまとめて移動した場合は、tokenの保存先だけが移りclient設定が残るなど、対応関係を失っていないかを調べます。secretやtokenの実値を比較表に貼る必要はありません。

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

原因候補確認する記録復旧前の整理
利用者が連携を取り消した利用者の操作・接続管理再同意の意図を確認
Testing条件に該当発行時状態・要求scope期限付き利用の設計を確認
client設定の取り違え環境別client識別子・設定参照元正しい組合せへ戻す
組織のsession条件error subtype・管理者方針方針に沿う再認証経路を確認

Google Cloudのsession controlが関係する場合、公式資料はinvalid_grantのerror_subtypeにinvalid_raptが含まれる例を示しています。すべてのGoogle API連携にこの説明を当てはめず、Cloud Platform scopeや組織方針が関係するかを確認します。

再認証は対象ユーザーと保存先を決めて行う

再認証が必要と判断したら、停止中の連携、同意するユーザー、OAuth client、必要scope、更新する保存先を対応表にします。失敗した一人のtokenを再取得するために、他ユーザーの保存済みtokenまで削除しません。

  1. 自動再試行を制限し、失敗した連携だけを再認証が必要な状態へ切り替える。
  2. 正しい環境のclientと必要scopeで利用者を再認証へ案内する。
  3. 成功応答の内容を確認し、新しいrefresh tokenが返った場合に安全な保存先を更新する。
  4. tokenが返らない応答で保存値を空に上書きしない。連携ライブラリの保存処理を確認する。
  5. 保存後、後続のrefresh経路と必要最小限のAPI読取を確認する。

初回ログインが成功しても、別workerが古い保存値を読み続けていれば復旧は終わっていません。キャッシュ、環境別DB、定期処理の設定元を含め、どの実行主体が新しい認証情報を読むかを確認します。具体的な保存・暗号化方法は利用中の認証ライブラリと運用方式に合わせます。

復旧完了と再発防止を分けて記録する

復旧記録には、対象連携、原因として確認できた事実、未確認事項、再認証した範囲、次の定期処理の確認結果を残します。エラーが消えた事実だけで原因を確定しません。

短期の再発防止は、refresh失敗を利用者へ分かる状態にすること、無効tokenを無限再送しないこと、発行時のclient・scope・環境を秘密値なしで追えることです。長時間のサーバー処理にユーザー認証情報を使う設計が組織のsession条件と合わない場合は、認証方式自体を別の設計課題として見直します。

確認した公式資料