Repository navigation
Description
Summary
The experimental DBSC implementation generates refresh and session cookie schemes from a source cookie scheme, but the generated schemes do not inherit an explicitly configured DataProtectionProvider from that source. Their tickets are protected with the application's default data protection provider instead of the provider configured for the source scheme.
Related to #66478 (DBSC tracking), #68117 (API proposal), and #69618 (derived session cookie path inheritance). The implementation was removed from .NET 11 by #69462 and backported by #69479, so this issue tracks a requirement for any future DBSC reintroduction rather than a .NET 11 servicing change.
What is wrong
- Generated refresh and session schemes should use the same data protection configuration as their source scheme unless the application explicitly configures them differently.
PostConfigureDeviceBoundSessionDerivedCookieOptions.CopyFromSourcecopies cookie attributes and lifetime settings but notDataProtectionProvider.- Copying the provider only in the existing post-configure step would still be too late.
AddCookieregistersPostConfigureCookieAuthenticationOptionsfirst; that component assigns the default provider and builds the fallbackTicketDataFormatbefore DBSC's post-configure runs. - The
AddDeviceBoundSessionsurface does not document that generated schemes otherwise fall back to the default provider.
Why it matters
- Applications that configure a dedicated provider on the source scheme, such as a dedicated key ring, application name, or key protection, expect credentials derived from that scheme to use the same protection configuration.
- In deployments where only the source scheme's provider is persisted or shared across instances, derived DBSC cookies can fail to unprotect after restart or on another instance even though source cookies work.
Affected code
Permalinks point to b3d5795c6f, the last main commit before the DBSC removal.
PostConfigureDeviceBoundSessionDerivedCookieOptions.cs:80-92-CopyFromSourceomitsDataProtectionProvider.PostConfigureDeviceBoundSessionDerivedCookieOptions.cs:30-56- generated-scheme post-configuration entry point.DeviceBoundSessionExtensions.cs:84-96- generated refresh and session schemes registered throughAddCookie.DeviceBoundSessionExtensions.cs:120-122- DBSC options components registered only asIPostConfigureOptions.PostConfigureCookieAuthenticationOptions.cs:30-45- core cookie post-configure assigns the default provider and buildsTicketDataFormat.CookieExtensions.cs:79- registration that places the core cookie post-configure ahead of DBSC's.DeviceBoundSessionCookieProtectionTests.cs:57-88- existing coverage for per-scheme protection keying, but not provider inheritance.Microsoft.AspNetCore.Authentication.DeviceBoundSessions0.11.0-rc.1.26425.128- experimental prerelease package containing the implementation.
Recommended fix
Assign the source provider during named configuration, before PostConfigureCookieAuthenticationOptions builds the fallback ticket format. Preserve an explicit derived-scheme provider or ticket format, and leave ticket-format construction to the core cookie post-configure so each generated scheme keeps its scheme-specific protector purpose.
private void InheritDataProtection(string sourceScheme, CookieAuthenticationOptions target)
{
if (target.DataProtectionProvider is not null ||
target.TicketDataFormat is not null)
{
return;
}
var source = _services.GetRequiredService<IOptionsMonitor<CookieAuthenticationOptions>>().Get(sourceScheme);
target.DataProtectionProvider = source.DataProtectionProvider;
}- Have the derived-options component also implement
IConfigureNamedOptions<CookieAuthenticationOptions>, apply the helper only to generated refresh and session scheme names, and register it for both named configuration and post-configuration inAddDeviceBoundSessionCore. - Keep application configuration authoritative: an explicit provider or ticket format on a generated scheme is left unchanged.
- Document inheritance and override semantics on
AddDeviceBoundSession.
Alternatives considered:
- Copy the provider in the existing post-configure step only. Rejected because the fallback
TicketDataFormatalready exists by then. - Reuse the source scheme's
TicketDataFormatinstance. Rejected because it removes the per-scheme purpose separation between source, refresh, and session tickets. - Require applications to configure each generated scheme. Rejected because generated scheme names are an implementation detail and the current surface does not disclose that requirement.
- Open question: define the expected derived-scheme behavior when the source uses a custom
TicketDataFormatwithout a provider, or aSessionStore(see DBSC: share source scheme ITicketStore (server-side revocation) with derived cookies #67794).
Compatibility: no public API change is expected. After the change, derived cookies previously protected with a different provider will no longer unprotect, and affected browsers must re-register or re-authenticate. Because the package is experimental and removed from .NET 11, apply this before any future DBSC package is published.
Acceptance criteria
- When the source scheme has an explicit
DataProtectionProvider, tickets issued by the generated refresh and session schemes are protected with that provider rather than the application-default provider. - An explicitly configured
DataProtectionProviderorTicketDataFormaton a generated scheme is preserved. - Source, refresh, and session tickets remain non-interchangeable;
DerivedCookieSchemes_RemainDataProtected_AndSchemeKeyedcontinues to pass. - Behavior without an explicit source provider is unchanged.
- Tests exercise the real
AddCookieandAddDeviceBoundSessionregistration path, not only directPostConfigurecalls, so options-pipeline ordering is covered. -
AddDeviceBoundSessiondocumentation describes provider inheritance and override semantics. - Support Device Bound Session Credentials (DBSC) #66478 records this requirement before DBSC is reintroduced.
Activity
rokonec commentedon Oct 6, 2026
Note for the fix: this issue also affects the challenge protector, not only the derived cookies.
DeviceBoundSessionChallengeProtectorbuilds its registration and refresh protectors from the application-defaultIDataProtectionProvider, and it is registered as a single singleton. After this issue is fixed, derived cookies would use the source scheme's provider while challenges would still use the default one. With a dedicated or persisted source provider, cookies would still unprotect after a restart or on another instance while challenges would not.The challenge purposes (
…Challenge.Registration.v1and…Challenge.Refresh.v1) also do not include the DBSC scheme name, unlike the derived cookie tickets, whose purpose chain includes the scheme name. With several DBSC schemes, a challenge from one scheme therefore unprotects on another when the principal (and session id) match.Inheriting the provider is orthogonal to purpose isolation, so this change does not weaken per-scheme separation, as long as the derived tickets keep their scheme-specific purpose as proposed here. The challenge protector should follow the same model: root it in the source scheme's effective provider and add the DBSC scheme name to its purpose chain.
I am tracking the multi-scheme work, including this Data Protection isolation, in a new issue linked below.
Tracking issue: #69682