Skip to content

OAuth re-authorization required after idle period despite refresh token flow #242

Description

@liplus-lin-lay

目的

アイドル後の MCP 呼び出しで「Authentication failed after retry. Please re-authenticate.」が発生し、再認証を行わないまま自然復旧した事象を記録する。エラーメッセージが要求する対処(再認証)を実施せずに回復しているため、少なくともエラー表示が実態と乖離している。

観測(2026-07-27、Li+ セッション中)

確認できた事実のみを記す。

  1. セッション前半(webhook イベントの受信時刻で 04:43〜05:53 帯)、mark_processed を複数回連続で呼び出し、すべて成功
  2. 09:40 頃、mark_processed を2件呼び出し、両方が失敗。エラー文字列は Authentication failed after retry. Please re-authenticate.
  3. 人間がブラウザで GitHub のログイン画面に遭遇し、ログインを実施。ただし MCP の OAuth 再認可(トークンの再認証)は行っていない。
  4. その後 get_pending_status および mark_processed を呼び出し、すべて成功(以降 14 件連続成功、本 issue 起票時点まで再発なし)。

未確定事項

  • 3 のログインと 4 の回復に因果関係があるかは不明。GitHub サイトへのログインは MCP の OAuth grant の再発行とは別経路であり、無関係である可能性が高いが、確認していない。
  • 前半の最終成功から失敗までの間隔は概ね4時間だが、その間 MCP を呼び出していないため、token / grant が実際に無効化された時刻は特定できない。

前提(既存実装)

  • @cloudflare/workers-oauth-provider を使用
  • accessTokenTTL: 3600(1時間) / refreshTokenTTL: 30 * 24 * 3600(30日)
  • refresh token 交換フローは実装済み(Fix authentication loop when refresh token expires #183 で 401 リトライの無限再帰・空文字列 refresh token を修正)

評価

再認証なしで回復している以上、grant が恒久的に失われたわけではない。したがって当初疑った「token 失効でブラウザ再認可が必要な状態」とは異なる。

より整合する読みは、refresh 経路の一時的な失敗である。エラー文字列 Authentication failed after retry はクライアント側が既にリトライした上で諦めたことを示すが、その後の呼び出しは成功しているため、リトライ回数ないしバックオフが実際の回復時間に足りていない可能性がある。

この読みが正しければ、実害は「一時的な失敗が、恒久的な認証切れとして人間に提示される」というエラー表示の誤りであり、人間に不要な対処(再認証・設定変更)を促す。実際、本セッションでは GitHub App の設定変更を検討する段階まで進みかけた。

関連する既存 issue(いずれも CLOSED)

本件は #187 と異なり自然復旧している点で症状が分かれる。#183 が扱ったリトライ経路の残余である可能性がある。

切り分け方針

次回発生時に取るべきデータ:

  1. 失敗直前の最終成功時刻・失敗時刻・回復時刻の3点を記録する。回復までに人間の操作が挟まっていないことを明示的に確認する(今回はここが曖昧になった)。
  2. Cloudflare Workers Observability のログで、失敗時に invalid_grant / Grant not found が出ているか、あるいは別の失敗理由かを確認する。
  3. クライアント側のリトライ回数・バックオフ間隔と、実際の回復までの経過時間を突き合わせる。

代替案(採用しない、記録のみ)

姉妹リポ github-rag-mcp は token 失効問題に対し、GitHub App の Optional features「User-to-server token expiration」を Opt-out して解決している(判断記録は liplus-language wiki の github-app-user-to-server-token-expiration)。

本リポでは採用しない。rag-mcp は refresh フロー未実装だったため Opt-out が唯一の低コスト解だったが、本リポは refresh を実装済みである。加えて本件は自然復旧しており token 失効とは症状が異なるため、Opt-out は的を外している。

備考

本 issue は修正ではなく観測の記録である。データ点が1件のみで周期性が未確認。

起票時の初版は「人間による再認可で解消した」と記述していたが、これは事実確認を経ない推測であり誤りだった。人間の指摘により訂正済み。切り分け方針 1 に「人間の操作が挟まっていないことの確認」を明示的に加えたのはこのため。

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions