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 URI | refresh 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 / Testing | 7日条件を調べる対象か |
| 要求した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まで削除しません。
- 自動再試行を制限し、失敗した連携だけを再認証が必要な状態へ切り替える。
- 正しい環境のclientと必要scopeで利用者を再認証へ案内する。
- 成功応答の内容を確認し、新しいrefresh tokenが返った場合に安全な保存先を更新する。
- tokenが返らない応答で保存値を空に上書きしない。連携ライブラリの保存処理を確認する。
- 保存後、後続のrefresh経路と必要最小限のAPI読取を確認する。
初回ログインが成功しても、別workerが古い保存値を読み続けていれば復旧は終わっていません。キャッシュ、環境別DB、定期処理の設定元を含め、どの実行主体が新しい認証情報を読むかを確認します。具体的な保存・暗号化方法は利用中の認証ライブラリと運用方式に合わせます。
復旧完了と再発防止を分けて記録する
復旧記録には、対象連携、原因として確認できた事実、未確認事項、再認証した範囲、次の定期処理の確認結果を残します。エラーが消えた事実だけで原因を確定しません。
短期の再発防止は、refresh失敗を利用者へ分かる状態にすること、無効tokenを無限再送しないこと、発行時のclient・scope・環境を秘密値なしで追えることです。長時間のサーバー処理にユーザー認証情報を使う設計が組織のsession条件と合わない場合は、認証方式自体を別の設計課題として見直します。
