Problem
When multiple Device Bound Sessions are active on the same site, it is possible to construct a scenario where two or more sessions enter a cyclic deadlock during token refresh, potentially causing network requests to hang indefinitely.
This scenario was reproduced in Chromium (https://crbug.com/495096658) and the symptoms look similar to previously reported #252 .
According to the current specification, a network request is deferred when it targets a URL within a session's scope and the session requires a refresh. While a session explicitly excludes its own refresh_url from its scope (preventing self-deadlock, §8.2.4), it does not automatically exclude the refresh_url of other sessions.
If two sessions (Session A and Session B) have overlapping scopes such that:
- Session A's
refresh_url falls into the scope of Session B.
- Session B's
refresh_url falls into the scope of Session A.
- Both sessions simultaneously require a refresh (e.g., cookies expired or deleted).
Any request triggering a refresh for Session A will be deferred, initiating a refresh request to Session A's refresh_url. This refresh request will in turn be deferred by Session B, initiating a refresh request to Session B's refresh_url. Finally, this request will be deferred by Session A, leading to a deadlock.
Potential solutions
We can address this issue in several ways, ranging from simple policy adjustments to more complex runtime checks.
Option 1: Make refresh requests non-deferrable (Recommended)
The simplest and most robust solution is to specify that DBSC refresh requests are exempt from all DBSC deferrals.
Behavior: When a user agent issues a refresh request for any session, it must bypass scope matching and deferral checks for all other DBSC sessions.
Pros: Very simple to implement; completely eliminates the possibility of cyclic deadlocks caused by overlapping session maintenance.
Cons: May send refresh requests without cookies from other potentially active sessions on the same origin. Prevents websites from "chaining" DBSC sessions.
Option 2: Deferral timeout
Strongly encourage user agents to introduce a timeout for how long any network request can be held in a deferred state.
Behavior: If a request is deferred for longer than a specific threshold, the user agent fails the request or sends it without waiting for the refresh.
Pros: Protects against deadlocks and unresponsive servers simultaneously.
Cons: Does not prevent the deadlock from occurring in the first place; introduces arbitrary latency, flakiness, and potential race conditions.
Option 3: Cycle detection
The user agent could track the dependency graph of deferred requests to detect when a cycle is forming.
Behavior: If a refresh request would be deferred by a session that is already in the deferral chain, the user agent aborts or bypasses the deferral.
Pros: Preserves scope isolation and session layering more strictly.
Cons: Significantly more complex to specify and implement; requires maintaining a global dependency state.
Problem
When multiple Device Bound Sessions are active on the same site, it is possible to construct a scenario where two or more sessions enter a cyclic deadlock during token refresh, potentially causing network requests to hang indefinitely.
This scenario was reproduced in Chromium (https://crbug.com/495096658) and the symptoms look similar to previously reported #252 .
According to the current specification, a network request is deferred when it targets a URL within a session's scope and the session requires a refresh. While a session explicitly excludes its own
refresh_urlfrom its scope (preventing self-deadlock, §8.2.4), it does not automatically exclude therefresh_urlof other sessions.If two sessions (Session A and Session B) have overlapping scopes such that:
refresh_urlfalls into the scope of Session B.refresh_urlfalls into the scope of Session A.Any request triggering a refresh for Session A will be deferred, initiating a refresh request to Session A's
refresh_url. This refresh request will in turn be deferred by Session B, initiating a refresh request to Session B'srefresh_url. Finally, this request will be deferred by Session A, leading to a deadlock.Potential solutions
We can address this issue in several ways, ranging from simple policy adjustments to more complex runtime checks.
Option 1: Make refresh requests non-deferrable (Recommended)
The simplest and most robust solution is to specify that DBSC refresh requests are exempt from all DBSC deferrals.
Behavior: When a user agent issues a refresh request for any session, it must bypass scope matching and deferral checks for all other DBSC sessions.
Pros: Very simple to implement; completely eliminates the possibility of cyclic deadlocks caused by overlapping session maintenance.
Cons: May send refresh requests without cookies from other potentially active sessions on the same origin. Prevents websites from "chaining" DBSC sessions.
Option 2: Deferral timeout
Strongly encourage user agents to introduce a timeout for how long any network request can be held in a deferred state.
Behavior: If a request is deferred for longer than a specific threshold, the user agent fails the request or sends it without waiting for the refresh.
Pros: Protects against deadlocks and unresponsive servers simultaneously.
Cons: Does not prevent the deadlock from occurring in the first place; introduces arbitrary latency, flakiness, and potential race conditions.
Option 3: Cycle detection
The user agent could track the dependency graph of deferred requests to detect when a cycle is forming.
Behavior: If a refresh request would be deferred by a session that is already in the deferral chain, the user agent aborts or bypasses the deferral.
Pros: Preserves scope isolation and session layering more strictly.
Cons: Significantly more complex to specify and implement; requires maintaining a global dependency state.