Skip to content

Key Vault challenge-based authentication fails to extract tenant ID from DSTSv2 authority URIs #48088

@christothes

Description

@christothes

Key Vault challenge-based authentication fails to extract tenant ID from DSTSv2 authority URIs

Summary

The Key Vault challenge-based authentication policy incorrectly parses the tenant ID from WWW-Authenticate challenge responses when the authorization URI uses a DSTSv2 (Distributed Security Token Service v2) authority format. This causes authentication failures when connecting to Key Vault endpoints that return DSTSv2 challenges.

Background

When a Key Vault client makes an unauthenticated request, the service responds with a 401 Unauthorized containing a WWW-Authenticate header like:

Bearer authorization="https://login.microsoftonline.com/{tenantId}", resource="https://vault.azure.net"

The client parses the authorization URI to extract the tenant ID (typically the first path segment) and uses it to acquire a token.

The Bug

The current implementation assumes the tenant ID is always the first path segment of the authorization URI. This is correct for standard Entra ID (AAD) authorities:

https://login.microsoftonline.com/{tenantId}/oauth2/authorize
                                  ^^^^^^^^^
                                  Segments[1] = tenantId ✅

However, DSTSv2 authority URIs have a different path layout where dstsv2 is the first path segment and the tenant ID is the second:

https://uswest2-passive-dsts.dsts.core.windows.net/dstsv2/{tenantId}
                                                   ^^^^^^ ^^^^^^^^^
                                                   Seg[1]  Seg[2] = tenantId

With the current logic, the extracted "tenant ID" is the literal string dstsv2 instead of the actual GUID, causing token acquisition to fail or target the wrong tenant.

Example challenge header from a DSTSv2 endpoint

Bearer authorization="https://uswest2-passive-dsts.dsts.core.windows.net/dstsv2/de763a21-49f7-4b08-a8e1-52c8fbc103b4", resource="https://foo.bar.core.windows.net"

Expected Behavior

The tenant ID should be correctly extracted as de763a21-49f7-4b08-a8e1-52c8fbc103b4, regardless of whether the authority URI is a standard Entra ID endpoint or a DSTSv2 endpoint.

Fix Description

When parsing the authorization URI to extract the tenant ID:

  1. Extract the first path segment as usual.
  2. If the first path segment equals dstsv2 (case-insensitive) and there is a subsequent path segment, use that subsequent segment as the tenant ID instead.

Pseudocode

tenantId = authorizationUri.pathSegments[1]  // e.g. "dstsv2" or a GUID

if tenantId.equalsIgnoreCase("dstsv2") AND pathSegments.length > 2:
    tenantId = authorizationUri.pathSegments[2]

Affected Area

This bug is in the Key Vault challenge-based authentication policy — the component that handles the 401 → parse challenge → acquire token → retry flow. In each language SDK, this is typically:

Language Approximate Location
.NET ChallengeBasedAuthenticationPolicy.ChallengeParameters constructor
Python ChallengeAuthPolicy / HttpChallenge class
Java KeyVaultCredentialPolicy
JavaScript/TypeScript challengeBasedAuthenticationPolicy / challenge parsing utilities
Go challengePolicy / challenge parsing in azkeys, azsecrets, azcertificates

Reference Fix

The .NET fix is in Azure/azure-sdk-for-net#56416.

Key change in ChallengeBasedAuthenticationPolicy.cs:

TenantId = authorizationUri.Segments[1].Trim('/');
if (TenantId.Equals("dstsv2", StringComparison.OrdinalIgnoreCase) && authorizationUri.Segments.Length > 2)
{
    TenantId = authorizationUri.Segments[2].Trim('/');
}

Suggested Test Case

Simulate a Key Vault challenge response with a DSTSv2 authorization URI and verify the tenant ID is correctly extracted:

  1. Mock a 401 response with header:
    WWW-Authenticate: Bearer authorization="https://uswest2-passive-dsts.dsts.core.windows.net/dstsv2/{expectedTenantGuid}", resource="https://foo.bar.core.windows.net"
    
  2. Mock a 200 response for the subsequent authenticated request.
  3. Capture the tenant ID passed to the credential's getToken call.
  4. Assert the captured tenant ID equals the expected GUID, not the literal string "dstsv2".

Labels

KeyVault, bug, client

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageWorkflow: This is a new issue that needs to be triaged to the appropriate team.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions