Console redirects to sign-in during concurrent session refresh

オープン
#42,535 コメント 3 件 リアクション 1 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
45/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
nextjs, python, typescript

調査の方向性

Read hydration-boundary.tsx, web/app/auth/refresh/route.ts, web/service/refresh-token.ts, account_login_service.py, and account_login_adapters.py to trace concurrent refresh handling. Reproduce overlapping refresh requests and inspect navigation plus refresh responses. Done means valid shared sessions converge without unnecessary sign-in redirects, while expired or revoked sessions still recover in a bounded way without loops.

索引モデルが issue の本文から書いたものです。

説明

🐞 bug cloud status: deferred web
Self Checks
  • I have read the Contributing Guide and Language Policy.
  • This is only for bug report, if you would like to ask a question, please head to Discussions.
  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report, otherwise it will be closed.
  • 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :)
  • Please do not modify this template :) and fill in all the required fields.
Dify version

1.17.1 on Dify Cloud, observed on September 18, 2026. API and Web image tags were hotfix-1.17.1-fix.0; the API trace's service.version was dify-1.17.1-9f6153c3d55aaa60e0e7e46078da54f9765f9376.

The source paths discussed below were rechecked against main at 5568aa0ea57d3a2c1cec03bd747b975494f094e3 on September 19. The refresh route, client refresh helper, and backend session refresh/rotation files are unchanged between these two revisions. Runtime reproduction was on Cloud, not a build of the latest main.

Cloud or Self Hosted

Cloud

Steps to reproduce

Concurrent Console session refresh can navigate an authenticated browser to /signin, even though a usable session remains available. This report tracks that recovery behavior separately from the login-page cache loop in #38457.

  1. Sign in to https://cloud.dify.ai/ and verify that the Console home page is accessible.
  2. In the same browser profile/context, create a set of eight test tabs so that they share authentication cookies with the signed-in tab.
  3. Dispatch navigation in these eight test tabs concurrently to https://cloud.dify.ai/auth/refresh?redirect_url=%2F (the test used a parallel batch of browser navigation calls).
  4. Inspect navigation history as well as final URLs. A final Home page alone can hide a preceding sign-in redirect.
  5. Correlate this window with complete API access logs for POST /console/api/refresh-token; successful and rejected refresh requests can be absent from sampled traces.

This was a targeted concurrency test in the Codex in-app browser. It deliberately invokes the existing refresh route with a logged-in session; it does not reproduce the full natural access-token-expiry sequence. A preceding two-tab attempt ended at Home in both tabs. The eight-tab attempt also eventually ended at Home, but its history recorded:

2026-09-18T11:30:01.343Z
Sign in - Dify
https://cloud.dify.ai/signin?redirect_url=%2F

The issue is timing-dependent; one observed eight-tab run is not a measured reproduction rate. No cookies were manually deleted, no logout endpoint was invoked, and no application data was changed during this test.

✔️ Expected Behavior

Concurrent refresh attempts for a shared browser session should converge on a usable renewed session without unnecessarily navigating an already-authenticated user to sign-in.

A regression test should cover overlapping refresh-route requests, browser API refresh overlapping with server-side refresh, and out-of-order responses. Genuinely expired or revoked sessions should still require authentication, with bounded recovery and no redirect loop.

❌ Actual Behavior

At least one navigation passed through /signin during the concurrent test before all test tabs returned to Home. This demonstrates an unnecessary authentication redirect; it does not by itself demonstrate permanent session revocation.

Additional production evidence

The investigation began with a user reporting unexpected logout. The associated Console request sequence included:

2026-09-18 09:57:41.398 UTC  GET  /console/api/explore/apps  401  (server span)
2026-09-18 09:57:41.756 UTC  POST /console/api/refresh-token 200  (access log)
2026-09-18 09:57:42.791 UTC  GET  /console/api/explore/apps  200  (access log)

The account associated with the successful retry subsequently had 35 authenticated API requests returning 200 through 09:59:14 UTC. Separately, complete access logs contain a server-side refresh from a Web pod returning 401 at 09:57:46.149 UTC; it has no corresponding sampled trace. That internal request lacks a session correlation identifier, so it cannot be conclusively attributed to the original user.

Refresh 200s and 401s were also present in the concurrent browser test window. Those log queries covered shared production traffic: exact per-test success/failure counts are not claimed without a unique correlation key. Private account identifiers, cookie values, internal addresses, and observability links are omitted.

Relevant implementation and candidate mechanism

This is a source-supported candidate explanation for the observed redirect, not a claim that every request in the original incident used the same refresh token. The full original logout and its precise interleaving still need request-level correlation. Simply serializing rotation may still reject callers already carrying a superseded token; recovery semantics need to handle that case without weakening revocation.

Related work

  • #38457 and draft PR #38458 cover the sign-in profile-cache redirect loop. The PR changes the login-page probe, not backend refresh rotation or server/client refresh coordination.
  • #30827 / merged PR #30828 address a browser refresh-lock deadlock.
  • PR #41914 proposes dead-token/sign-in-loop handling, but was closed without merging and does not address backend rotation.

From Codex

主要言語
TypeScript
スター
157k
フォーク
24.7k
平均マージ
22時間 32分
マージ済み PR(30日)
611

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

langgenius/dify のほかの issue

langgenius/dify の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。