Skip to content

DBSC: full support for multiple DBSC schemes, including testing and validation #69682

Agent suggestions

Public preview

Description

@rokonec

Summary

The experimental DBSC implementation (Microsoft.AspNetCore.Authentication.DeviceBoundSessions) was designed and tested around a single DBSC scheme wrapping a single source cookie scheme. AddDeviceBoundSession is callable multiple times, but multi-scheme behavior was never specified, implemented end to end, or validated. This issue tracks full support for multiple DBSC schemes, including design, implementation, testing, and validation, as a requirement for any reintroduction of DBSC.

Related to #66478 (DBSC tracking), #68117 (API proposal), #68520 (scheme-convention alignment), #69619 (derived cookies should inherit the source DataProtectionProvider), and #67794 (shared ITicketStore). The implementation was removed from .NET 11 by #69462, so this tracks a requirement for the reintroduction rather than a servicing change. Code links refer to the last main commit before the removal, b3d5795c6f.

Problem: Data Protection isolation is only partially scheme-scoped

DBSC protects data in two places, and they behave differently with several schemes.

Protected value Created by Purpose chain includes the scheme?
Refresh cookie Cookie authentication (derived scheme {source}.Dbsc.Refresh) Yes: CookieAuthenticationMiddleware, {derivedScheme}, v2
Session cookie Cookie authentication (derived scheme {source}.Dbsc.Session) Yes
Registration challenge DeviceBoundSessionChallengeProtector No: fixed …Challenge.Registration.v1
Refresh challenge DeviceBoundSessionChallengeProtector No: fixed …Challenge.Refresh.v1

Consequences with two or more DBSC schemes:

  • A challenge minted for scheme A unprotects successfully on scheme B. The only binding is the principal claim UID (and the session id for refresh), not the scheme. Registration and refresh challenges are separated from each other by purpose, but not between schemes.
  • DeviceBoundSessionChallengeProtector is registered once as a singleton (DeviceBoundSessionExtensions.AddDeviceBoundSessionCore) and uses the application-default IDataProtectionProvider. It cannot use a different provider per DBSC scheme.
  • DeviceBoundSessionHandler also constructs its own DeviceBoundSessionChallengeProtector instance, while DeviceBoundSessionRegistrationHeader resolves the DI singleton to mint the registration challenge. The two only agree today because both use the default provider.
  • Once DBSC derived cookie schemes should inherit the source scheme's DataProtectionProvider #69619 makes derived cookies use the source scheme's provider, challenges would still use the default provider. With a dedicated or persisted source provider, cookies would survive a restart or another instance while challenges would not.

Affected code:

  • DeviceBoundSessionChallengeProtector.cs (constructor): fixed purposes, no scheme.
  • DeviceBoundSessionHandler.cs (constructor): creates its own challenge protector from the default provider.
  • DeviceBoundSessionRegistrationHeader.cs: resolves the singleton challenge protector.
  • DeviceBoundSessionExtensions.cs (AddDeviceBoundSessionCore): TryAddSingleton<DeviceBoundSessionChallengeProtector>().
  • PostConfigureCookieAuthenticationOptions.cs (core cookies): shows the scheme-keyed purpose that DBSC cookies already get.

Recommended direction: make challenge protection per DBSC scheme and rooted in the source scheme's effective DataProtectionProvider, with the DBSC scheme name in the purpose chain.

var provider = cookieOptionsMonitor.Get(options.RegistrationSourceScheme).DataProtectionProvider;
provider.CreateProtector(
    "Microsoft.AspNetCore.Authentication.DeviceBoundSessions.Challenge.Registration.v1",
    dbscSchemeName);

The handler already has Options.RegistrationSourceScheme and an IOptionsMonitor<CookieAuthenticationOptions>, and the registration header already receives the resolved DBSC scheme, so one per-scheme protector (for example from a factory or cache keyed by scheme) can serve both. Changing the purposes invalidates in-flight challenges, which is acceptable because the package is experimental.

Other multi-scheme areas to specify and validate

Data Protection is not the only area. The following also need an explicit design and tests:

  • Endpoint path collisions. RegistrationPath and RefreshPath default to the same values (/.well-known/dbsc/registration and /refresh) for every DBSC scheme. HandleRequestAsync matches on method and path only, so with default paths the first handler registered answers every request, and registration or refresh runs against the wrong source scheme. Options validation only checks that registration and refresh differ within one scheme. Decide between per-scheme paths, a distinguishing component, or failing fast on a cross-scheme collision.
  • Refresh cookie path scoping. The derived refresh cookie path is the directory of the scheme's RefreshPath. Confirm that cookies of different schemes sharing a directory do not interfere, and that paths remain correct under a path base. Related to DBSC derived session cookie should preserve source cookie path #69618 and DBSC: separate browser-advertised endpoint URLs from local handler paths #67850.
  • Default authenticate scheme handling. PostConfigureDeviceBoundSessionAuthenticationOptions only upgrades the app's default authenticate scheme when it matches a DBSC source scheme. Define behavior for apps using several DBSC source schemes, including per-request forwarding (DBSC session authentication does not preserve the source scheme's per-request forwarding #69620).
  • Shared state in DeviceBoundSessionSourceSchemes. The scheme maps are keyed by source scheme. Define and test behavior when the same source scheme is registered twice or when derived names collide, and fail with a clear error.
  • Per-scheme source configuration. Source schemes may differ in cookie settings, DataProtectionProvider, TicketDataFormat, SessionStore (DBSC: share source scheme ITicketStore (server-side revocation) with derived cookies #67794), and events. Derived schemes must follow their own source, not another one.
  • Registration exchange guard. DeviceBoundSessionCookieEvents.RegistrationExchangeItemKey is a single HttpContext.Items key. Confirm it cannot suppress sign-out handling for a different scheme within one request.
  • Documentation. Document the supported multi-scheme topologies and their limits, including Data Protection behavior and path configuration.

Acceptance criteria

  • A registration challenge issued for DBSC scheme A is rejected by scheme B, even when both schemes share the same DataProtectionProvider and the same principal.
  • A refresh challenge issued for scheme A is rejected by scheme B, even with the same principal and session id.
  • Challenges use the effective DataProtectionProvider of their own source scheme. A challenge minted under a dedicated provider cannot be validated under the application-default provider, and the reverse also fails.
  • Challenge minting (registration header) and validation (handler) resolve the same per-scheme protector.
  • Source, refresh, and session cookies of all schemes remain pairwise non-interchangeable (extends DerivedCookieSchemes_RemainDataProtected_AndSchemeKeyed).
  • Two DBSC schemes with the default paths either work correctly or fail at startup with a clear message. Requests are never handled by the wrong scheme.
  • Registration, refresh, session cookie issuance, and sign-out work independently for two DBSC schemes within one app, each with its own source scheme and settings.
  • Tests use the real AddCookie and AddDeviceBoundSession registration pipeline, not only direct PostConfigure calls, so options ordering is covered. They cover at least two schemes, with both shared and distinct providers.
  • An end-to-end validation with two schemes is documented, using the DbscDebugServer sample or equivalent, to confirm the browser flow.
  • Multi-scheme behavior and its limits are documented, and Support Device Bound Session Credentials (DBSC) #66478 records this requirement before DBSC is reintroduced.

Activity

  1. added
    area-authIncludes: authentication, authorization, OAuth, OIDC, and access token validation
    on Oct 6, 2026
  2. github-actions commented on Oct 6, 2026

    @github-actions
    Contributor

    Triage Summary

    Area: area-auth (DBSC cookie authentication schemes; already labeled)
    Type: Feature (requests design and implementation of multi-scheme DBSC support)

    Potential Duplicates

    • None found

    Generated by Issue Triage Agent for dotnet/aspnetcore for #69682 · copilot · auto · 27.9 AIC · ⌖ 2.68 AIC · ⊞ 33.3K · ◷

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-authIncludes: authentication, authorization, OAuth, OIDC, and access token validation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions