Console redirects to sign-in during concurrent session refresh
まだ誰も着手していません。
評価
- 難易度
- 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 の本文から書いたものです。
説明
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.
- Sign in to
https://cloud.dify.ai/and verify that the Console home page is accessible. - In the same browser profile/context, create a set of eight test tabs so that they share authentication cookies with the signed-in tab.
- 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). - Inspect navigation history as well as final URLs. A final Home page alone can hide a preceding sign-in redirect.
- 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
- Console SSR profile admission redirects a profile 401 to
/auth/refresh. - The refresh route forwards the incoming Cookie header to the API, then redirects to sign-in on any non-OK result or exception. It does not recheck whether another request has already renewed the browser session.
- Backend refresh resolves the refresh token before rotation deletes the old mapping and issues new tokens. These are separate operations; a request carrying the old cookie can resolve after another request has deleted its mapping and receive 401.
- Browser refresh coordination uses client memory/localStorage and does not coordinate requests handled by the server-side refresh route.
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
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
langgenius/dify のほかの issue
-
Annotation Reply: a stored score threshold of 0.0 is silently replaced with 1, disabling the feature オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
langgenius/dify#42639 · コメント 1 件 · リアクション 1 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
langgenius/dify#42468 · コメント 1 件 · リアクション 1 件 ·
-
🐞 bug
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
langgenius/dify#42446 · リアクション 1 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
langgenius/dify#42355 · コメント 1 件 · リアクション 1 件 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
langgenius/dify#42350 · コメント 1 件 · リアクション 1 件 ·
langgenius/dify の issue をすべて見る
似ている issue
-
calcite-components needs triage refactor
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
Esri/calcite-design-system#15203 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 91/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
難易度 1/5 1時間未満 初心者へのやさしさ 95/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
Automattic/studio#4908 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 90/100