Skip to content

fix(oauth): stale in-memory token blocks re-auth for the life of the proxy process #250

Description

@smileygames

目的

ブラウザで認可を完了し、新しいトークンが保存されているのに、起動中の中継プログラムが Authentication required を返し続ける再認証ループを解消する。ブラウザの完了表示も実際のトークン交換・保存の結果を反映させる。

前提と観測

2026-08-21 の報告・確認は本Issueのコメントに残っている。2026-09-30にも同じ症状が再発した。

  • 実行中の npm パッケージは github-rag-mcp 0.11.0。中継のOAuth処理はリポジトリの mcp-server/server/index.js と同じ構造。
  • ブラウザは localhost callback で Authorization successful を表示するが、現在のコードはtoken endpointへの交換・保存より先にこのレスポンスを送る。
  • 実際に認可後の oauth-tokens.json は更新され、その保存済みトークンを新しいremote clientで使った検索は成功(isError=false、count=1)。既存MCPプロセスの検索はその直前に Authentication required を返した。
  • getAccessToken() はメモリキャッシュが falsy の時だけファイルを読む。refresh失敗後も古いキャッシュを保持し、performOAuthFlow() が2〜3秒でpendingエラーを返すと代入は行われない。
  • callback完了時に保存してpendingをnullにしても、メモリキャッシュの古い値を更新する経路がない。このため次の呼び出しが新しい認可を始める。
  • 同じホームの複数プロセスが同じtoken/client registrationファイルを共有している。別プロセスで更新された有効なトークンを古いメモリ値で覆い隠してはならない。

根拠: mcp-server/server/index.js の startOAuthFlow / performOAuthFlow / getAccessToken / onUnauthorized、本Issueの2026-08-21コメント、2026-09-30の保存済みトークンによる実検索。

要求と制約

  • 認可完了後の次のMCP呼び出しは保存された新しいトークンを利用し、同じ理由で再びブラウザを開かない。
  • refresh失敗や401で無効と判明したトークンを、キャッシュまたはディスクからそのまま再採用し続けない。
  • 有効な既存トークンは引き続き利用できる。別プロセスによる更新も取り込める。
  • pendingのタイムアウト、失敗、完了を呼び出し側へ安全に伝え、処理が停止したり未処理Promise rejectionを起こしたりしない。
  • ブラウザの成功表示はtoken交換と保存成功後に出す。交換や保存の失敗は成功表示にしない。
  • トークン、OAuth code/state/verifier、secret入りURLをログ、Issue、PR、テスト結果に出さない。
  • MCPのstdio/HTTPプロトコル、検索の意味、既存のユーザー設定を維持する。原因が未確定のApp切替やissuer不一致を今回の原因と断定しない。
  • 公開リリース・バージョン変更はこの修正のマージとは別の人間確認。今回の実機には検証済み修正版を可逆的に適用して検索復旧を確認する。

検証

古いキャッシュ・refresh失敗・遅れて完了する認可の組み合わせを再現し、完了後の再呼び出しが新しいトークンを利用する回帰テスト。別プロセスによるファイル更新、401後の無効トークン再読込、交換/保存失敗とブラウザ表示も検証する。テストでは実在する認証情報を使わない。

対象ファイル

  • mcp-server/server/index.js、必要なOAuth処理モジュール
  • mcp-server/test/ とテスト実行設定
  • 動作仕様を所有する該当ドキュメント

関連

#176 はランダムなcallback portとclient registrationの修理。本Issueは完了後のtoken/cache状態を扱う。

Activity

  1. added
    bug動いていない、壊れている
    forming本文を再構築しながら要求を整えている状態
    on Aug 20, 2026
  2. smileygames commented on Aug 20, 2026

    @smileygames
    MemberAuthor

    実地確認(2026-08-21)

    Master が Claude Desktop を再起動した直後に search を呼んだところ、通った。認可操作は何も行っていない。ディスク上のトークン(07:45 更新)はそのままである。

    これは本文の推定機構を経験的に確定させる:

    • 認可フローは完走しており、有効なトークンはディスクに在った。
    • それでも呼び出しが弾かれ続けていたのは、メモリ上の _cachedTokens が古い値を保持し、ディスクの読み直しを塞いでいたためである。
    • プロセスが死ぬと当該変数も死ぬため、再起動後の最初の呼び出しは loadTokens() を通り、07:45 のトークンを拾って成立した。

    再起動は回避路であって修理ではない。修理されるまで、同じ状態は「refresh が失敗する状況」(App 差し替え直後、refresh token の期限切れ、grant の失効)が起きるたびに再現する。

    なお、本 issue 本文が推定として書いた「旧 App 由来で refresh が通らない」の側は、この観測では確定していない。確定したのはメモリ上の古い値がディスクの新しい値を覆い隠すという一点である。

  3. added
    ready本文が実装開始できる形まで収束している状態。ただし更新は継続可能
    and removed
    forming本文を再構築しながら要求を整えている状態
    on Sep 30, 2026
  4. self-assigned this
    on Sep 30, 2026
  5. added
    in-progress着手中、実装または検証が進行中
    waiting外部依存待ち(CI / dependent issue / 環境)。pause 状態
    and removed
    in-progress着手中、実装または検証が進行中
    on Sep 30, 2026
  6. lipluscodex commented on Sep 30, 2026

    @lipluscodex
    Member

    PR #258、head 96978eb の CI 完了を待っています。bridge 33 件、既存 Worker 382 件、型チェック、schema drift、dry-run build はローカルで成功済み。実機の認証・設定・process は変更していません。

  7. added
    review-pending実装フェーズ完了。orchestration (brake eval / review / merge / close) 待ち
    in-progress着手中、実装または検証が進行中
    and removed
    waiting外部依存待ち(CI / dependent issue / 環境)。pause 状態
    review-pending実装フェーズ完了。orchestration (brake eval / review / merge / close) 待ち
    on Sep 30, 2026
  8. lipluscodex commented on Sep 30, 2026

    @lipluscodex
    Member

    Lin: PR #258 の修正をこのPCへ適用し、Codex再起動後に本チャットのMCP検索成功を確認しました。古いトークンによるループの修理と実機復旧が完了したため閉じます。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bug動いていない、壊れているin-progress着手中、実装または検証が進行中ready本文が実装開始できる形まで収束している状態。ただし更新は継続可能

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions