title: Trying to make some sense out of all variants of token credentials while getting tokens for Azure Key Vault
body: <p>I'm building a Web API using .Net 5. The Web API is protected by Azure AD and is accessible by a single tenant. The Web API will connect to other Azure resources (Storage, Cosmos DB etc.), the connection strings of those are stored in Azure Key Vault as secrets.</p>
  <p>My objective is to fetch these connection strings (secrets) from Azure Key Vault on API startup and use those to connect to these resources. When the Web API will get deployed to production, it will use <code>managed identity</code> to connect to the Key Vault and get the secrets. During development, I would like to use some other mechanisms to connect and get the secrets. I do not want to create a <code>Service Principal</code> and use client id/client secret for that purpose.</p>
  <p>I wondered how I would accomplish the connectivity during development and that's when I found out about different mechanisms to get tokens. However when I used them, I ran into a number of issues and now I am confused about using them.</p>
  <h2>1. ChainedTokenCredential</h2>
  <p>While researching, I ran into <a href="https://channel9.msdn.com/Events/dotnetConf/2020/Secretless-Development-from-Local-to-Cloud-with-the-New-Azure-SDKs-Project-Tye-and-Kubernetes" rel="nofollow noreferrer"><code>Secretless Development from Local to Cloud with the New Azure SDKs, Project Tye, and Kubernetes</code></a> video and subsequently <a href="https://github.com/jongio/memealyzer" rel="nofollow noreferrer"><code>memealyzer</code></a> project where I came to know about <a href="https://docs.microsoft.com/en-us/dotnet/api/azure.identity.chainedtokencredential?view=azure-dotnet" rel="nofollow noreferrer"><code>ChainedTokenCredential</code></a>. Based on my understanding, you can chain multiple token credentials and the SDK will try to connect to each one of the token credentials until it succeeds. This sounded perfect to me and I ended up implementing code similar to below:</p>
  <pre><code>ChainedTokenCredential chainedTokenCredential = new ChainedTokenCredential(
      new ManagedIdentityCredential(),
      new VisualStudioCredential()
      );
  SecretClient client = new SecretClient(new Uri(&quot;https://mykv.vault.azure.net&quot;), chainedTokenCredential);
  KeyVaultSecret secret = await secretClient.GetSecretAsync(&quot;mysecretkeyname&quot;);
  </code></pre>
  <p>As per my understanding, if I run the code above in Visual Studio the code should first try to make use of <code>ManagedIdentityCredential()</code> (which will fail) and then <code>VisualStudioCredential()</code> (which should succeed because I am signed in into Visual Studio with an account that has access to the Key Vault secrets.</p>
  <p>However to my surprise the code threw the following exception:</p>
  <pre><code>    Azure.Identity.CredentialUnavailableException: The ChainedTokenCredential failed to retrieve a token from the included credentials. 
      - ManagedIdentityCredential authentication unavailable. No Managed Identity endpoint found. 
  </code></pre>
  <p>The exception makes sense as I am running the code locally. However it is my understanding that the SDK will automatically try the next credential provider in the chain if there's an exception. In my case, I was expecting the code to try <code>VisualStudioCredential</code> automatically if getting token via <code>ManagedIdentityCredential</code> failed. However that is not happening.</p>
  <h2>2. VisualStudioCredential</h2>
  <p>Next I commented out <code>ManagedIdentityCredential()</code> and just used <a href="https://docs.microsoft.com/en-us/dotnet/api/azure.identity.visualstudiocredential?view=azure-dotnet" rel="nofollow noreferrer"><code>VisualStudioCredential</code></a> thinking that it would work considering I am signed in into Visual Studio using correct credentials.</p>
  <p><img src="https://i.stack.imgur.com/XBqkB.png" alt="enter image description here" /></p>
  <pre><code>ChainedTokenCredential chainedTokenCredential = new ChainedTokenCredential(
      //new ManagedIdentityCredential(),
      new VisualStudioCredential()
      );
  SecretClient client = new SecretClient(new Uri(&quot;https://mykv.vault.azure.net&quot;), chainedTokenCredential);
  KeyVaultSecret secret = await secretClient.GetSecretAsync(&quot;mysecretkeyname&quot;);
  </code></pre>
  <p>However that also failed with the following error:</p>
  <pre><code>Azure.Identity.CredentialUnavailableException: Operating system Darwin 20.3.0 Darwin Kernel Version 20.3.0: Thu Jan 21 00:06:51 PST 2021; root:xnu-7195.81.3~1/RELEASE_ARM64_T8101 isn't supported.
  </code></pre>
  <h2>3. AzureCliCredential</h2>
  <p>Baffled, I replaced <code>VisualStudioCredential</code> with <a href="https://docs.microsoft.com/en-us/dotnet/api/azure.identity.azureclicredential?view=azure-dotnet" rel="nofollow noreferrer"><code>AzureCliCredential</code></a> and tried again. I have installed the latest version of Azure CLI (2.21.0) and I logged in into Azure CLI using <code>az login</code> command both in an external terminal and terminal inside Visual Studio.</p>
  <p><img src="https://i.stack.imgur.com/JQSbZ.png" alt="enter image description here" /></p>
  <pre><code>ChainedTokenCredential chainedTokenCredential = new ChainedTokenCredential(
      //new ManagedIdentityCredential(),
      new AzureCliCredential()
      );
  SecretClient client = new SecretClient(new Uri(&quot;https://mykv.vault.azure.net&quot;), chainedTokenCredential);
  KeyVaultSecret secret = await secretClient.GetSecretAsync(&quot;mysecretkeyname&quot;);
  </code></pre>
  <p>However that also failed with the following error:</p>
  <pre><code>Azure.Identity.CredentialUnavailableException: Azure CLI not installed 
  </code></pre>
  <p>Which does not make any sense considering Azure CLI is installed and I am logged in there.</p>
  <h2>4. DefaultAzureCredential</h2>
  <p>Supremely confused and frustrated, I finally decided to use <a href="https://docs.microsoft.com/en-us/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet" rel="nofollow noreferrer"><code>DefaultAzureCredential</code></a> thinking that it is my last resort. However I did not create any app registration in Azure AD etc. and simply executed the following code:</p>
  <pre><code>SecretClient client = new SecretClient(new Uri(keyVaultConfiguration.VaultUri), new DefaultAzureCredential());
  KeyVaultSecret secret = await secretClient.GetSecretAsync(&quot;mysecretkeyname&quot;);
  </code></pre>
  <p>Now here I was expecting the code to fail but to my surprise the code worked (mysteries of Azure Identity, I guess :)) and I was able to get secrets. I am wondering why the above code worked and which token credential did it pick (considering I am both signed in into Visual Studio and Azure CLI using same credentials).</p>
  <h2>Development Environment</h2>
  <ul>
  <li>IDE: <code>Visual Studio version 8.9.4 (build 25)</code></li>
  <li>OS: <code>macOS Big Sur (11.2.3) [Apple Silicon]</code></li>
  <li>SDK: <code>Azure.Identity (version 1.3.0)</code></li>
  </ul>
  <h2>Questions</h2>
  <p>Thank you for reading so far (it turned out to be a really long post). To summarize, here are my questions:</p>
  <ol>
  <li>What am I doing wrong in the 1st 3 cases?</li>
  <li>Why did the <code>ChainedTokenCredential</code> implementation failed on <code>ManagedIdentityCredential</code> and did not continue to the next one? Did I misunderstand the implementation of <code>ChainedTokenCredential</code>?</li>
  <li>Why did the <code>VisualStudioCredential</code> implementation failed with <code>not supported platform</code> error?</li>
  <li>Why did the <code>AzureCliCredential</code> implementation failed with <code>Azure CLI not installed</code> error when it is definitely installed and I am signed in into it.</li>
  <li>Lastly, without doing anything special, why did <code>DefaultAzureCredential</code> implementation worked? Also, which credentials did it pick?</li>
  </ol>
  <p>Any insights into this will be highly appreciated.</p>