Hi,
In my application I am getting exception when my application fetches value of first key vault secret.
The exception I am only getting when I turn on "Common Language Run-time Exceptions" from exception settings.
Exception that I am getting is-
Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException: 'Response status code indicates server error: 401 (Unauthorized).'
StackTrace:-
at Microsoft.Rest.RetryDelegatingHandler.<>c__DisplayClass11_0.<<SendAsync>b__1>d.MoveNext()
My code to fetch the key vault secret is given below-
public async Task<string> GetSecretValue(string clientId, string appKey, string secretIdentifier)
{
IAdAuthentication authToken = new AdAuthentication
{
ClientId = clientId,
AppKey = appKey
};
KeyVaultClient keyVaultClient = new KeyVaultClient(authToken.GetAuthenticationTokenAsync);
// Get secret from the KeyVault.
SecretBundle secret = await keyVaultClient.GetSecretAsync(secretIdentifier);
string secretValue = string.Empty;
if (secret?.Value != null)
{
secretValue = secret.Value.Trim();
}
return secretValue;
}
Interface IAdAuthentication
public interface IAdAuthentication
{
string ClientId { get; set; }
string AppKey { get; set; }
/// <summary>
/// Get Authentication Token
/// </summary>
/// <param name="authority"></param>
/// <param name="resource"></param>
/// <param name="scope"></param>
/// <returns></returns>
Task<string> GetAuthenticationTokenAsync(string authority, string resource, string scope);
}
Implementation of interface IAdAuthentication is in class AdAuthentication
public class AdAuthentication : IAdAuthentication
{
public string ClientId { get; set; }
public string AppKey { get; set; }
/// <summary>
/// Get Authentication Token
/// </summary>
/// <param name="authority"></param>
/// <param name="resource"></param>
/// <param name="scope"></param>
/// <returns></returns>
public async Task<string> GetAuthenticationTokenAsync(string authority, string resource, string scope)
{
if (string.IsNullOrEmpty(authority))
throw new ArgumentNullException(nameof(authority));
if (string.IsNullOrEmpty(resource))
throw new ArgumentNullException(nameof(resource));
if (string.IsNullOrEmpty(ClientId))
throw new ArgumentNullException(nameof(ClientId));
if (string.IsNullOrEmpty(AppKey))
throw new ArgumentNullException(nameof(AppKey));
ClientCredential clientCredential = new ClientCredential(ClientId, AppKey);
AuthenticationContext context = new AuthenticationContext(authority, false, TokenCache.DefaultShared);
AuthenticationResult result = await context.AcquireTokenAsync(resource, clientCredential);
return result.AccessToken;
}
}
Above given exception is being thrown when I fetch the value of first key vault secret for the application instance and it doesn't matter what is the value of first secret identifier. For all next key vault secret exception doesn't occur.
Along with exception value of first key vault secret is also being fetched but I want to mitigate this exception from my application.
It seems issue is around AuthenticationCallback which is passed to initialize KeyVaultClient.
Please let me know what I am missing here.
Adding details of fiddler tracing for the key vault secret request-
CONNECT mykeyvault.vault.azure.net:443 HTTP/1.0
Host: mykeyvault.vault.azure.net:443
Content-Length: 0
Proxy-Connection: Keep-Alive
Pragma: no-cache
A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.
Version: 3.3 (TLS/1.2)
Random: 5B D6 D9 74 4F 81 32 0A 1D CB 8F DF E2 1F 2A 87 EC C2 98 A7 CA 6F EF DF 50 4E 1F 11 7D D7 7D 8F
"Time": 2/15/2032 10:17:23 AM
SessionID: empty
Extensions:
server_name mykeyvault.vault.azure.net
status_request OCSP - Implicit Responder
elliptic_curves unknown [0x1D), secp256r1 [0x17], secp384r1 [0x18]
ec_point_formats uncompressed [0x0]
signature_algs sha256_rsa, sha384_rsa, sha1_rsa, sha256_ecdsa, sha384_ecdsa, sha1_ecdsa, sha1_dsa, sha512_rsa, sha512_ecdsa
SessionTicket empty
ALPN h2, http/1.1
extended_master_secret empty
0x0018 00 10 03 02 01 00
renegotiation_info 00
Ciphers:
[C02C] TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
[C02B] TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
[C030] TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
[C02F] TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
[C024] TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
[C023] TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
[C028] TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
[C027] TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
[C00A] TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
[C009] TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
[C014] TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA
[C013] TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA
[009D] TLS_RSA_WITH_AES_256_GCM_SHA384
[009C] TLS_RSA_WITH_AES_128_GCM_SHA256
[003D] TLS_RSA_WITH_AES_256_CBC_SHA256
[003C] TLS_RSA_WITH_AES_128_CBC_SHA256
[0035] TLS_RSA_AES_256_SHA
[002F] TLS_RSA_AES_128_SHA
[000A] SSL_RSA_WITH_3DES_EDE_SHA
Compression:
[00] NO_COMPRESSION
HTTP/1.1 200 Connection Established
Proxy-Agent: Zscaler/5.6
Encrypted HTTPS traffic flows through this CONNECT tunnel. HTTPS Decryption is enabled in Fiddler, so decrypted sessions running in this tunnel will be shown in the Web Sessions list.
Secure Protocol: Tls12
Cipher: Aes256 256bits
Hash Algorithm: Sha384 ?bits
Key Exchange: RsaKeyX 2048bits
== Server Certificate ==========
[Subject]
CN=vault.azure.net
[Issuer]
[email protected], CN=Zscaler Intermediate Root CA (zscaler.net), OU=Zscaler Inc., O=Zscaler Inc., S=California, C=US
[Serial Number]
7B00004CD55FB23FA0B68D46B8000000009CD5
[Not Before]
9/13/2017 6:31:29 AM
[Not After]
9/13/2019 6:31:29 AM
[Thumbprint]
BE3A3F50134F9E3989C4200C751X473D5235F4C2
[SubjectAltNames]
vault.azure.net, *.vault.azure.net, *.vaultcore.azure.net
------------------------------------------------------------------
GET https://mykeyvault.vault.azure.net/secrets/ContactManager-AppApiUrl/?api-version=7.0 HTTP/1.1
User-Agent: FxVersion/4.6.00001.0 OSName/Windows OSVersion/MicrosoftWindows Microsoft.Azure.KeyVault.KeyVaultClient/3.0.1.0
Host: mykeyvault.vault.azure.net
Connection: Keep-Alive
Cache-Control: no-cache
HTTP/1.1 401 Unauthorized
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/10.0
WWW-Authenticate: Bearer authorization="https://login.windows.net/e41ed7bb-472e-4682-9ac0-dd00dfe1aa40", resource="https://vault.azure.net"
x-ms-keyvault-region: eastus2
x-ms-request-id: b3baba90-222c-4412-b57e-b5500ff95572
x-ms-keyvault-service-version: 1.1.0.858
x-ms-keyvault-network-info: addr=165.225.34.51;act_addr_fam=InterNetwork;
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Strict-Transport-Security: max-age=31536000;includeSubDomains
X-Content-Type-Options: nosniff
Date: Mon, 29 Oct 2018 09:57:08 GMT
Content-Length: 0
Proxy-Support: Session-Based-Authentication
------------------------------------------------------------------
CONNECT login.windows.net:443 HTTP/1.0
Host: login.windows.net:443
Content-Length: 0
Proxy-Connection: Keep-Alive
Pragma: no-cache
A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.
Version: 3.3 (TLS/1.2)
Random: 5B D6 D9 7C 94 3B 8E 2B 32 4F 6F 70 3F 85 EC C0 53 27 5D C8 5C 3E 33 8F CF 38 30 A4 91 F8 AE 16
"Time": 5/17/2036 8:59:31 PM
SessionID: empty
Extensions:
server_name login.windows.net
status_request OCSP - Implicit Responder
elliptic_curves unknown [0x1D), secp256r1 [0x17], secp384r1 [0x18]
ec_point_formats uncompressed [0x0]
signature_algs sha256_rsa, sha384_rsa, sha1_rsa, sha256_ecdsa, sha384_ecdsa, sha1_ecdsa, sha1_dsa, sha512_rsa, sha512_ecdsa
SessionTicket empty
ALPN h2, http/1.1
extended_master_secret empty
0x0018 00 10 03 02 01 00
renegotiation_info 00
Ciphers:
[C02C] TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
[C02B] TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
[C030] TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
[C02F] TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
[C024] TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
[C023] TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
[C028] TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
[C027] TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
[C00A] TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
[C009] TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
[C014] TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA
[C013] TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA
[009D] TLS_RSA_WITH_AES_256_GCM_SHA384
[009C] TLS_RSA_WITH_AES_128_GCM_SHA256
[003D] TLS_RSA_WITH_AES_256_CBC_SHA256
[003C] TLS_RSA_WITH_AES_128_CBC_SHA256
[0035] TLS_RSA_AES_256_SHA
[002F] TLS_RSA_AES_128_SHA
[000A] SSL_RSA_WITH_3DES_EDE_SHA
Compression:
[00] NO_COMPRESSION
HTTP/1.1 200 Connection Established
Proxy-Agent: Zscaler/5.6
Encrypted HTTPS traffic flows through this CONNECT tunnel. HTTPS Decryption is enabled in Fiddler, so decrypted sessions running in this tunnel will be shown in the Web Sessions list.
Secure Protocol: Tls12
Cipher: Aes256 256bits
Hash Algorithm: Sha384 ?bits
Key Exchange: RsaKeyX 2048bits
== Server Certificate ==========
[Subject]
CN=graph.windows.net
[Issuer]
[email protected], CN=Zscaler Intermediate Root CA (zscaler.net), OU=Zscaler Inc., O=Zscaler Inc., S=California, C=US
[Serial Number]
200003E3D42591706F9A74181400000003E3D4
[Not Before]
8/29/2018 12:38:12 PM
[Not After]
8/29/2020 12:38:12 PM
[Thumbprint]
27242CE7B9E88BD32DE00CB02BF2033B3AX47DDD
[SubjectAltNames]
*.accesscontrol.windows.net, *.accesscontrol.windows-ppe.net, *.b2clogin.com, *.cpim.windows.net, *.microsoftaik.azure.net, *.microsoftaik-int.azure-int.net, *.windows-ppe.net, aadg.windows.net, aadgv6.ppe.windows.net, aadgv6.windows.net, account.live.com, account.live-int.com, api.password.ccsctp.com, api.passwordreset.microsoftonline.com, autologon.microsoftazuread-sso.com, becws.ccsctp.com, clientconfig.microsoftonline-p.net, clientconfig.microsoftonline-p-int.net, companymanager.ccsctp.com, companymanager.microsoftonline.com, cpim.windows.net, device.login.microsoftonline.com, device.login.windows-ppe.net, directoryproxy.ppe.windows.net, directoryproxy.windows.net, graph.ppe.windows.net, graph.windows.net, graphstore.windows.net, login.live.com, login.live-int.com, login.microsoft.com, login.microsoftonline.com, login.microsoftonline-p.com, login.microsoftonline-pst.com, login.microsoft-ppe.com, login.windows.net, logincert.microsoftonline.com, logincert.microsoftonline-int.com, login-us.microsoftonline.com, microsoftaik.azure.net, microsoftaik-int.azure-int.net, nexus.microsoftonline-p.com, nexus.microsoftonline-p-int.com, pas.windows.net, pas.windows-ppe.net, password.ccsctp.com, passwordreset.activedirectory.windowsazure.us, passwordreset.microsoftonline.com, provisioning.microsoftonline.com, signup.live.com, signup.live-int.com, sts.windows.net, xml.login.live.com, xml.login.live-int.com, *.login.microsoftonline.com, login.microsoftonline-int.com, accesscontrol.aadtst3.windows-int.net, *.accesscontrol.aadtst3.windows-int.net
------------------------------------------------------------------
GET https://login.windows.net/common/discovery/instance?api-version=1.1&authorization_endpoint=https://login.windows.net/e41ed7bb-472e-4682-9ac0-dd00dfe1aa40/oauth2/authorize HTTP/1.1
client-request-id: dc9c444d-5a14-4e0c-a8af-fa5ad44930e0
return-client-request-id: true
x-client-DM: VMware Virtual Platform
Accept: application/json
x-client-Ver: 4.3.0.0
x-ms-PKeyAuth: 1.0
x-client-CPU: x64
x-client-SKU: PCL.UAP
Host: login.windows.net
Connection: Keep-Alive
Cache-Control: no-cache
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/json; charset=utf-8
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
client-request-id: dc9c444d-5a14-4e0c-a8af-fa5ad44930e0
x-ms-request-id: cbd2d6c4-57af-4e90-8e8c-fec278b74b00
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
Set-Cookie: esctx=AQABAAAAAAC5una0EUFgTIF8ElaxtWjTyrZcJfJlYlmLZhgPyiVeColz5g03S9fX_lMIQxsDqOLcD48dBrq1lzrwm_R5KQ0aQwBpyf41EMKYybbS9bJF1EARNWl5u68rj09wRyg8VoIcIntNSzLIVCP-M-GM1o5BdHUfESmTTmFObRSnAewkoTTHEyeILstPRJxRPWUFlxkgAA; domain=.login.windows.net; path=/; secure; HttpOnly
Set-Cookie: x-ms-gateway-slice=003; path=/; secure; HttpOnly
Set-Cookie: stsservicecookie=ests; path=/; secure; HttpOnly
Date: Mon, 29 Oct 2018 09:57:15 GMT
Content-Length: 967
{"tenant_discovery_endpoint":"https://login.windows.net/e41ed7bb-472e-4682-9ac0-dd00dfe1aa40/.well-known/openid-configuration","api-version":"1.1","metadata":[{"preferred_network":"login.microsoftonline.com","preferred_cache":"login.windows.net","aliases":["login.microsoftonline.com","login.windows.net","login.microsoft.com","sts.windows.net"]},{"preferred_network":"login.partner.microsoftonline.cn","preferred_cache":"login.partner.microsoftonline.cn","aliases":["login.partner.microsoftonline.cn","login.chinacloudapi.cn"]},{"preferred_network":"login.microsoftonline.de","preferred_cache":"login.microsoftonline.de","aliases":["login.microsoftonline.de"]},{"preferred_network":"login.microsoftonline.us","preferred_cache":"login.microsoftonline.us","aliases":["login.microsoftonline.us","login.usgovcloudapi.net"]},{"preferred_network":"login-us.microsoftonline.com","preferred_cache":"login-us.microsoftonline.com","aliases":["login-us.microsoftonline.com"]}]}
------------------------------------------------------------------
GET https://mykeyvault.vault.azure.net/secrets/ContactManager-AppApiUrl/?api-version=7.0 HTTP/1.1
x-ms-client-request-id: 639b8a72-c739-48c3-b9c3-f60a5ed8fa86
User-Agent: FxVersion/4.6.00001.0 OSName/Windows OSVersion/MicrosoftWindows Microsoft.Azure.KeyVault.KeyVaultClient/3.0.1.0
accept-language: en-US
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dDI7Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N5SEpsWSIsImtpZCI6Imk2bEdrM0ZaenhSY1ViMkMzbkVRN3N9SEpsWSJ9.eyJhdWQiOiJodPRwczovL3ZhdWx0LmF6dXJlLm5ldCIsImjzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkyMTEwMmEwLWI2MjEtNDM5Yy04NDY2LTdmZDU0MjE5YWU4Mi8iLCJpYXQiOjE1NDA4MDQyODIsIm5iZiI6MTU0MDgwNDI4MiwiZXhwIjoxNTQwODA4MTgyLCJhaW8iOiI0MlJnWUlnTys5WmZMcjV1cnl6djNUV3Jkd3ZjQXdBPSIsImFwcGlkIjoiZmJmMzdmNDktMTMxMC00N2JjLWE1ZjAtYmY4OWQ4NGUyYmE4IiwiYXBwaWRhY3IiOiIxIiwiZV9leHAiOjI2MjgwMCwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvOTIxMTAyYTAtYjYyMS00MzljLTg0NjYtN2ZkNTQyMTlhZTgyLyIsIm9pZCI6IjNiNWQ4OVY1LWNlMGItNGI4Ny1hZDVmLTVmNmUyZjM5N2E1ZSIsInN1YiI6IjNiNWQ4OWY1LWNlMGItNGI4Ny1hZDVmLTVmNmUyZjM5N2E1ZSIsInRpZCI6IjkyMTEwMmEwLWI2MjEtNDM5Yy04NDY2LTdmZDU0MjE5YWU4MiIsInV0aSI6IkhDMTJWZVBoV2tTNjJ5Z0Q1aFlfQUEiLCJ2ZXIiOiIxLjAifQ.Q36_4BxTPnvvZPO9LeTOl95u6CXpK1bmctUQfpFKwkrtMneFwqriCGHU9z_CseL-6uhGpUL_1m1MGUANr7r7HUoJwtteFY1SseTyfmvjjbwx9IkjMWwddV-95SVJxnlM54N6ol2Tn11bifDgSPbIPeDvaJ7JZSclk1FuqZItUdKGPwHHpGl2LP5gvtGbl-N_dypofLD1hZtH9DUFEtnt_ArCn_jN8nRblbe3vuLF9-MtiqF-rLt5Wx6s8gBo96boeBF7SL8weFjQfsNr_Q4ntX9o0IouywtW7rYp6Swo0j-OzfkDewuKBhqOheMtModX6xn1nvamVhldabz4Vjracg
Host: mykeyvault.vault.azure.net
Connection: Keep-Alive
Cache-Control: no-cache
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
x-ms-keyvault-region: eastus2
x-ms-request-id: d08a432e-00b4-4310-ab8b-90035e8e5626
x-ms-keyvault-service-version: 1.1.0.858
x-ms-keyvault-network-info: addr=165.225.34.51;act_addr_fam=InterNetwork;
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Strict-Transport-Security: max-age=31536000;includeSubDomains
X-Content-Type-Options: nosniff
Date: Mon, 29 Oct 2018 09:57:23 GMT
Content-Length: 270
{"value":"https://testserver.net:8476/api/","id":"https://mykeyvault.vault.azure.net/secrets/ContactManager-AppApiUrl/edd10997e4224a7cb756687e6318d972","attributes":{"enabled":true,"created":1535976474,"updated":1535976474,"recoveryLevel":"Purgeable"}}
------------------------------------------------------------------
Any updates on this one?
Anyone have any updates on this one?
Seems odd this is still open and there aren't more replies / participants / followers and votes. As far as i can tell this is the standard way to retrieve secrets from KeyVault. Is there something I'm missing?
Can of course work around this issue and ignore exception, but seems like a foundational bug in the SDK for KeyVault. I have not actually deployed my first app to Azure yet. Is this bug only going to occur in the IDE and maybe why it's not a hot issue?
You're not missing anything as far as I can tell. I get this also, from my App Service deployed to Azure every time it starts up. Issue opened Oct 24, 2018. No one assigned.
The original issue report describes by-design behavior. The Key Vault client makes an unauthenticated request to AKV. This request returns a 401 with authentication info in the WWW-Authenticate header. The retry handler used by the SDK throws and catches an exception as the response isn't a 2xx value. As this isn't retriable, we get the original 401 in our code, look at the WWW-Authenticate header, then call the user-provided authentication callback, passing in the values from that header. We cache these values, so this 401 only happens on the first request. The very beginning of the issue report says they only observe the exception when they change their debug settings to stop on any exception that is thrown. That exception is going to be caught and handled by the SDK.
"By-design" is not necessarily correct. This needs to be fixed. In my opinion, it is never acceptable practice to throw exceptions as part of normal operation, if for no other reason than that it will forever raise questions in users' minds.
The exception never leaves the shared REST SDK code. The exception is thrown and caught in the same function. It's internal to the design of the shared REST API client and how it determines if operations can be retried. As far as the AKV code is concerned, we call HttpClient.SendAsync and then check if response.StatusCode is HttpStatusCode.Unauthorized. The only reason the exception was observable is because the user turned on the option to see exceptions when they are thrown regardless of whether they're handled. This call still needs to go through the RetryDelegatingHandler in case there is an HTTP 500 response or a timeout, but there's no way to hint to it that a 401 is an expected response, so the retry handler wraps it in an exception, evaluates it against the transient error detection strategy, doesn't retry, catches the exception, and returns the original response. The exception never makes it back to the AKV SDK or to the user's code.
This isn't just when running under the debugger. It happens to my App Service running in Azure as well every time it accesses its key vault on startup. I see failures in my Application Map, for instance. Is there something I can do to hide it or exclude it from being logged in that case?
The 401 response is an expected and documented part of the Key Vault API. It is used to avoid hard coding the AAD login URL and AAD resource URI. Both of these are subject to change and by designing the SDK to discover their value from the WWW-Authenticate header in the 401 response allows these to be updated without requiring all customers to update their services (for example, in Azure Government cloud, the AAD URL changed from login-us.microsoftonline.com to login.microsoftonline.us). Tools like Application Insights that record all HTTP requests will observe that 401. I have not used Application Insights, but I did find a Stack Overflow post that describes how you can treat certain requests as successful.
In my case, I am getting a token by instantiating and using an AzureServiceTokenProvider provider object. That token is being supplied for the AuthenticationCallback class on the KeyVaultClient constructor. I think that would/should avoid this exception? But I am not setting the AzureAdInstance (We are NOT passing it into the AzureServiceTokenProvider constructor).
If you look at: Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider, the default is: "https://login.microsoftonline.com/". Not 100% sure that's right in our case, but I think it is.
I also see a constructor overload for KeyVaultClient which accepts an HttpClient. Perhaps if I retrieve a token from the client provider, create an HttpClient and pass it into the KeyVaultClient constructor that would solve the issue of the 401 exceptions showing up in AppInsights when things are starting up? This isn't something I have the capacity to attempt right now, so I'm asking - giving others ideas for a work around.
I don't care for this exception based programming from MS whether it's by design or not doesn't really matter to me - seems kludge.
You might upgrade to the Azure.Security.KeyVault.* packages which do not use exception-based flow for authentication. The DefaultAzureCredential from Azure.Identity makes this a trivial exercise, as authentication in general have been greatly improved. For example, you can simply do the following:
var client = new SecretClient(new Uri("https://myvault.vault.azure.net"), new DefaultAzureCredential());
KeyVaultSecret secret = await client.GetSecretAsync("mysecret");
Rather than handling the authentication callbacks yourself, would this be a better option? The older Microsoft.Azure.KeyVault* code will only be receiving critical fixes. The newer libraries have a lot of improvements, some (with more to come) described in https://aka.ms/azsdkvalueprop.
Although the exception never leaves the SDK, it has side effects:
In my case, it's happening with an HTTP 101 Switching Protocols response, which is not in any way erroneous, and the protocol I'm switching to is a streaming one that can't be read all at once.
I can't get too worked up about legitimately failed requests emitting trace output, but I think the determination of what requests are failed needs to be narrowed. In particular, 1xx responses should not be treated as failed. 3xx responses probably should not either. And as for 4xx responses, well many of them are used for normal communications and none of them should really be retried that I can see, except maybe HTTP 429. In general, I think only 5xx responses (and 429 and _maybe_ 423 Locked, but probably not) should trigger a retry.
Thank you for raising this issue. While the initial exception for the HTTP 401 response is expected in these older Microsoft.Azure.* packages, it is something we do not do in the newer Azure.* packages. The 401 is handled without throwing and the challenge is authenticated automatically using the DefaultAzureCredential or other TokenCredential classes you can use.
As for other HTTP response codes, these changes to Microsoft.Azure.* packages would be breaking behavior. Where Azure.* packages exist, we are only making critical updates to Microsoft.Azure.* packages and recommend that people upgrade. In this case, Azure.Security.KeyVault.Secrets would be what you want.
We are discussing what changes we might make to these newer Azure.* packages to improve performance in error conditions for performance-critical code. While Try-style methods are nice, out parameters cannot be used in async methods, which is what we recommend people use for better performance. When we have actionable proposals, we will open separate issues accordingly.
For anyone hoping that an upgrade to Azure.Security.KeyVault.Secrets package will get rid of the 401 error shown in Application Insights for the first secret request, I'm afraid I have bad news. It's still there. It still shows up as a failing call to Key Vault in the Application Map and the failure can be viewed in the dependencies table. This is with Azure.Security.KeyVault.Secrets version 4.2.0-beta.2, but we have the issue in 4.1.0 as well.
Most helpful comment
This isn't just when running under the debugger. It happens to my App Service running in Azure as well every time it accesses its key vault on startup. I see failures in my Application Map, for instance. Is there something I can do to hide it or exclude it from being logged in that case?