title: Getting a 403 when calling Azure Resource Rate API using certificate auth
body: <p>I am trying to create a console app that can call the <a href="https://msdn.microsoft.com/en-us/library/azure/mt219004" rel="nofollow noreferrer">Azure Resource Rate API</a> using certificate authentication. For this, I used the following branch <a href="https://github.com/HarvestingClouds/billing-dotnet-ratecard-api" rel="nofollow noreferrer">GitHub link</a>.</p>
  
  <p>I am getting a 403 error. I've added an Web App to my Azure AD. In the manifest, I've copied the key credentials from the certificate I've signed using the following PowerShell commands;</p>
  
  <pre><code>$cert=New-SelfSignedCertificate -Subject "CN=RateCardCert"
  -CertStoreLocation "Cert:\CurrentUser\My"  -KeyExportPolicy Exportable -KeySpec Signature  
  $bin = $cert.RawData $base64Value = [System.Convert]::ToBase64String($bin)
  $bin = $cert.GetCertHash() 
  $base64Thumbprint = [System.Convert]::ToBase64String($bin) 
  $keyid = [System.Guid]::NewGuid().ToString() 
  $jsonObj = @ customKeyIdentifier=$base64Thumbprint;keyId=$keyid;type="AsymmetricX509Cert";usage="Verify";value=$base64Value} 
  $keyCredentials=ConvertTo-Json @($jsonObj) | Out-File "keyCredentials.txt"
  </code></pre>
  
  <p>In de console app, I use the following function to get the token;</p>
  
  <pre><code>public static string GetOAuthTokenFromAAD_ByCertificate(string TenanatID, string ClientID, string CertificateName)
      {
          //Creating the Authentication Context
          var authContext = new AuthenticationContext(string.Format("https://login.windows.net/{0}", TenanatID));
          //Console.WriteLine("new authContext made");
          //Creating the certificate object. This will be used to authenticate
          X509Certificate2 cert = null;
          //Console.WriteLine("empty 'cert' made, null");
          //The Certificate should be already installed in personal store of the current user under 
          //the context of which the application is running.
          X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
  
  
          try
          {
              //Trying to open and fetch the certificate
              store.Open(OpenFlags.ReadOnly);
              var certCollection = store.Certificates;
              var certs = certCollection.Find(X509FindType.FindBySubjectName, CertificateName, false);
              //Checking if certificate found
              if (certs == null || certs.Count &lt;= 0)
              {
                  //Throwing error if certificate not found
                  throw new Exception("Certificate " + CertificateName + " not found.");
              }
              cert = certs[0];
          }
          finally
          {
              //Closing the certificate store
              store.Close();
          }
  
          //Creating Client Assertion Certificate object
          var certCred = new ClientAssertionCertificate(ClientID, cert);
  
          //Fetching the actual token for authentication of every request from Azure using the certificate
          var token = authContext.AcquireToken("https://management.core.windows.net/", certCred);
  
          //Optional steps if you need more than just a token from Azure AD
          //var creds = new TokenCloudCredentials(subscriptionId, token.AccessToken);
          //var client = new ResourceManagementClient(creds); 
  
          //Returning the token
          return token.AccessToken;
      }
  </code></pre>
  
  <p>This is the part of the code that makes the URL and puts in the request (the xxxx part is replaced by the ClientID of the webapp that I've registered in Azure AD);</p>
  
  <pre><code>//Get the AAD User token to get authorized to make the call to the Usage API
          string token = GetOAuthTokenFromAAD_ByCertificate("&lt;MyTenantName.onmicrosoft.com", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "RateCardCert");
  
  
              // Build up the HttpWebRequest
          string requestURL = String.Format("{0}/{1}/{2}/{3}",
                     ConfigurationManager.AppSettings["ARMBillingServiceURL"],
                     "subscriptions",
                     ConfigurationManager.AppSettings["SubscriptionID"],
                     "providers/Microsoft.Commerce/RateCard?api-version=2015-06-01-preview&amp;$filter=OfferDurableId eq 'MS-AZR-0044P' and Currency eq 'EUR' and Locale eq 'nl-NL' and RegionInfo eq 'NL'");
          HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL);
  
          // Add the OAuth Authorization header, and Content Type header
          request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
          request.ContentType = "application/json";
  
          // Call the RateCard API, dump the output to the console window
          try
          {
              // Call the REST endpoint
              Console.WriteLine("Calling RateCard service...");
              HttpWebResponse response = (HttpWebResponse)request.GetResponse();
              Console.WriteLine(String.Format("RateCard service response status: {0}", response.StatusDescription));
              Stream receiveStream = response.GetResponseStream();
  
              // Pipes the stream to a higher level stream reader with the required encoding format. 
              StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
              var rateCardResponse = readStream.ReadToEnd();
              Console.WriteLine("RateCard stream received.  Press ENTER to continue with raw output.");
              Console.ReadLine();
              Console.WriteLine(rateCardResponse);
              Console.WriteLine("Raw output complete.  Press ENTER to continue with JSON output.");
              Console.ReadLine();
  
              // Convert the Stream to a strongly typed RateCardPayload object.  
              // You can also walk through this object to manipulate the individuals member objects. 
              RateCardPayload payload = JsonConvert.DeserializeObject&lt;RateCardPayload&gt;(rateCardResponse);
  
              Console.WriteLine(rateCardResponse.ToString());
              response.Close();
              readStream.Close();
              Console.WriteLine("JSON output complete.  Press ENTER to close.");
              Console.ReadLine();
          }
          catch(Exception e)
          {
              Console.WriteLine(String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : ""));
              Console.ReadLine();
          }
  </code></pre>
  
  <p>I just don't know what I have to do anymore, what am I missing here??</p>
  
  <p>Full return of the console is:</p>
  
  <blockquote>
    <p>Calling RateCard Service...
    The remote server returned an error: (403) Forbidden.</p>
  </blockquote>