-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
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:
- Extract the first path segment as usual.
- 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:
- Mock a
401response with header:WWW-Authenticate: Bearer authorization="https://uswest2-passive-dsts.dsts.core.windows.net/dstsv2/{expectedTenantGuid}", resource="https://foo.bar.core.windows.net" - Mock a
200response for the subsequent authenticated request. - Capture the tenant ID passed to the credential's
getTokencall. - Assert the captured tenant ID equals the expected GUID, not the literal string
"dstsv2".
Labels
KeyVault, bug, client