Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure Billing Usage API returns 401 Unauthorized

I am using Azure REST API for fetching Billing Usage and Ratecard details. To acquire Token using AcquireToken() Method, initially I used only Client Id which then asks for User Credentials in login window.

However, I am looking for Non-Interactive Approach, so I used Client Credentials in which I passed Client Id and Client Secret Key.

But it gives "Remote Server returns an error 401 Unauthorized"

When I look into error deeply, I found that it gives error "The access token is from wrong audience or resource"

Please give me any solution using which I can access the API without any user interaction.

Thanks in Advance.

Here is my code:

{
    string token = GetOAuthTokenFromAAD();
    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&$filter=OfferDurableId eq 'MS-AZR-*****' and Currency eq 'INR' and Locale eq 'en-IN' and RegionInfo eq 'IN'");

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL);

    request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
    request.ContentType = "application/json";
    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    Console.WriteLine(String.Format("RateCard service response status: {0}", response.StatusDescription));
}

public static string GetOAuthTokenFromAAD()
{
      AuthenticationContext authenticationContext = new AuthenticationContext(string.Format("{0}/{1}",ConfigurationManager.AppSettings["ADALServiceURL"], ConfigurationManager.AppSettings["TenantDomain"]));

      AuthenticationResult result = null;
      ClientCredential uc = new ClientCredential(Client_Id, Secret_Key);
      try
      {
           result = authenticationContext.AcquireToken("https://management.core.windows.net/", uc);
      } 
      return result.AccessToken;
}

//App Config File
<add key="ADALServiceURL" value="https://login.microsoftonline.com" />
<add key="ADALRedirectURL" value="http://*****-authentication.cloudapp.net" />
<add key="ARMBillingServiceURL" value="https://management.core.windows.net" />
<add key="TenantDomain" value="********.onmicrosoft.com" />
<add key="SubscriptionID" value="*******-****-****-****-********" />
<add key="ClientId" value="*******-****-****-****-********" />
like image 977
Tejas Avatar asked Jan 01 '16 09:01

Tejas


People also ask

How to fix 401 unauthorized error Azure?

Make sure to provide a valid key for an active subscription." "statusCode": 401, "message": "Access denied due to missing subscription key. Make sure to include subscription key when making requests to an API."

What is Azure billing API?

The Azure Billing APIs allow you to view and manage your billing details programmatically. Operation groups listed below do not support all billing accounts. Supported billing accounts are specified in the table. To identify your billing account type, see Billing accounts and scopes.


1 Answers

Update: I have also provided these methods as a Reusable Authentication Helper Class Library. You can find the same at this link: Azure Authentication - Authenticating any Azure API Request in your Application

Method 1: To use the password approach non-interactively you need to first follow the below post's section "Authenticate with password - PowerShell": Authenticating a service principal with ARM

Then use the below code snippet to fetch token.

var authenticationContext = new AuthenticationContext(String.Format("{0}/{1}",
                                                                ConfigurationManager.AppSettings["ADALServiceURL"],
                                                                ConfigurationManager.AppSettings["TenantDomain"]));
        var credential = new ClientCredential(clientId: "11a11111-11a1-111a-a111-1afeda2bca1a", clientSecret: "passwordhere");
        var result = authenticationContext.AcquireToken(resource: "https://management.core.windows.net/", clientCredential: credential);

        if (result == null)
        {
            throw new InvalidOperationException("Failed to obtain the JWT token");
        }

        string token = result.AccessToken;

        return token;

Alternatively (Method 2), you can also use the certificate method. In that case use the same link as above but follow section "Authenticate with certificate - PowerShell" from that link. Then use the below code snippet to fetch the token non-interactively:

 var subscriptionId = "1a11aa11-5c9b-4c94-b875-b7b55af5d316";
        string tenant = "1a11111a-5713-4b00-a1c3-88da50be3ace";
        string clientId = "aa11a111-1050-4892-a2d8-4747441be14d";

        var authContext = new AuthenticationContext(string.Format("https://login.windows.net/{0}", tenant));

        X509Certificate2 cert = null;
        X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        string certName = "MyCert01";

        try
        {
            store.Open(OpenFlags.ReadOnly);
            var certCollection = store.Certificates;
            var certs = certCollection.Find(X509FindType.FindBySubjectName, certName, false);
            //var certs = certCollection.Find(X509FindType.FindBySerialNumber, "E144928868B609D35F72", false);
            if (certs == null || certs.Count <= 0)
            {
                throw new Exception("Certificate " + certName + " not found.");
            }
            cert = certs[0];
        }
        finally
        {
            store.Close();
        }

        var certCred = new ClientAssertionCertificate(clientId, cert);
        var token = authContext.AcquireToken("https://management.core.windows.net/", certCred);
        var creds = new TokenCloudCredentials(subscriptionId, token.AccessToken);
        //var client = new ResourceManagementClient(creds); 
        return token.AccessToken;
like image 174
Aman Sharma Avatar answered Oct 28 '22 01:10

Aman Sharma