3

I want to use the azure-vm-rest-api to create the VM from c#. My problem is I don't have clientID and tenantID. I just have my Microsoft username and password. I am trying this rest API from POSTMAN and I am successfully doing it. Means I have taken bearer token from the Deploy try it section. I want to generate it from the code.

using this portal to get the bearer token.

https://learn.microsoft.com/en-us/rest/api/resources/deployments/createorupdate (try it section) once I log in it will return me the bearer token. That bearer token I use in the postman calls.

Now I want how can I generate the bearer token from the C# so that I will pass it to REST API when calling it from C#. I don't have any client and tenant id.

Abhinav Sharma
  • 299
  • 1
  • 8
  • 20
  • Is your account a work account or a personal account? And do you mind creating an application in your Azure AD for getting access token? – Jack Jia Jul 12 '19 at 05:34
  • Work account.And do you mind creating an application in your Azure AD for getting access token?--Is that necessary to create an application in AD? There is no workaround that passing username and password I will get the bearer token. – Abhinav Sharma Jul 12 '19 at 05:38
  • There is a pre-defined application from Microsoft which you will use to sign in to Azure portal. I will write a sample to you later. – Jack Jia Jul 12 '19 at 05:49
  • Thanks @jack jia. I am looking forward to seeing this application. – Abhinav Sharma Jul 12 '19 at 05:52
  • Any update this issue? – Joy Wang Jul 15 '19 at 07:43
  • I have created one application in AD but I am getting errors;-Due to a configuration change made by your administrator, or because you moved to a new location, you must enroll in multi-factor authentication to access. Now I have clientID.tenantid also with me. And I am using the below-mentioned code. – Abhinav Sharma Jul 15 '19 at 09:04
  • Have you tried my solution? no need to create anything, the `Microsoft.Azure.Services.AppAuthentication` library uses your developer credentials to run in your local development environment. When the solution is deployed to Azure, the library uses a managed identity to switch to an OAuth 2.0 client credential grant flow. This means you can test the same code locally and remotely without worry. – Joy Wang Jul 16 '19 at 01:15
  • Thanks @JoyWang for this. It is working fine in local development. I am running this code in exe and I will run this exe in CD pipeline. When I run this application in CD so I received 403 status.I know because it is working in agent mode and agent is having some different account. – Abhinav Sharma Jul 16 '19 at 04:03
  • I am not familiar with azure devops, I recommend you to ask the specific question in another post. – Joy Wang Jul 16 '19 at 04:10
  • Looks you need to add the service principal related to the devops as a role to your subscription. – Joy Wang Jul 16 '19 at 04:21
  • 1
    Thanks JoyWang now my problem solved with your code. We have added our agent as a contributor in the Azure subscription. – Abhinav Sharma Jul 16 '19 at 06:14

3 Answers3

3

You could use Microsoft.Azure.Services.AppAuthentication library to do that.

static void Main(string[] args)
        {
            AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
            string accessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://management.azure.com/").Result;
            Console.WriteLine(accessToken);
        }

enter image description here

For more details about the authentication, you could refer to this link. Here is a similar sample to use the token to call the rest api, you can also take a look.

Joy Wang
  • 39,905
  • 3
  • 30
  • 54
2
public static string accessToken = string.Empty;     
 static void Main(string[] args)
            {
                try
                {
                    GetTokenWithoutSecretCode();
                    string url = "https://management.azure.com/subscriptions/SubscriptionID/resourcegroups/ResourceGroupName/providers/Microsoft.Resources/deployments/detdepoyment?api-version=2019-05-01";
                    string jsonContent = "{ \"properties\": {   \"templateLink\": {     \"uri\": \"https://storageName.blob.core.windows.net/templates/VMTemplate.json\",     \"contentVersion\": \"1.0.0.0\"   },   \"parametersLink\": {     \"uri\": \"https://storageName.blob.core.windows.net/templates/VMParam.json\",     \"contentVersion\": \"1.0.0.0\"   },   \"mode\": \"Incremental\" }}";
                    SpinupVM(url, jsonContent, accessToken);
                }
                catch (Exception ex)
                {
                    string message = ex.Message;
                    Console.WriteLine(ex.Message);
                    Console.ReadLine();
                }
            }

            private static void GetTokenWithoutSecretCode()
            {
                try
                {

                    AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
                    accessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://management.azure.com/").Result;
                }
                catch
                {
                    throw;
                }
            }

            // POST a JSON string
            private static void SpinupVM(string url, string jsonContent, string authToken)
            {
                JObject json = JObject.Parse(jsonContent);
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "PUT";
                request.Headers.Add("Authorization", "Bearer " + authToken);
                System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
                Byte[] byteArray = encoding.GetBytes(json.ToString());
                request.ContentLength = byteArray.Length;
                request.ContentType = "application/json";
                using (Stream dataStream = request.GetRequestStream())
                {
                    dataStream.Write(byteArray, 0, byteArray.Length);
                }
                long length = 0;
                try
                {
                    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                    {
                        length = response.ContentLength;
                    }
                }
                catch
                {
                    throw;
                }
            }

For Creating this VM, You must have proper rights for this. You must be added at least as a contributor for that resource group.

Abhinav Sharma
  • 299
  • 1
  • 8
  • 20
  • sorry @JoyWang, I apology. Now I accepted your answer. I did that mistake because I want that if anyone wants to do the same stuff in c# then it's a complete example(mine). – Abhinav Sharma Jul 19 '19 at 07:06
  • well, I up-vote your answer, I think others will find it. – Joy Wang Jul 19 '19 at 07:20
1
  1. You can get your tenant id from the Azure portal. You find it in this way: Azure Active Directory -> Properties -> Directory ID. But, in most cases, you can just use your tenant name, it is the part after the "@" in your account id. (***.onmicrosoft.com or your custom domain)

  2. Create a .NEt framework application and install the Microsoft.IdentityModel.Clients.ActiveDirectory package from nuget.

  3. The code:

    class Program
    {
        static void Main(string[] args)
        {
            string tenantId = "your tenant id or tenant name";
            string clientId = "1950a258-227b-4e31-a9cf-717495945fc2";
            string resource = "https://management.core.windows.net/";
            string username = "your work account, jack@hanxia.onmicrosoft.com";
            string password = "your password";

            var upc = new UserPasswordCredential(username, password);
            var context = new AuthenticationContext("https://login.microsoftonline.com/" + tenantId);
            AuthenticationResult result = context.AcquireTokenAsync(resource,clientId,upc).Result;
            Console.WriteLine(result.AccessToken);
            Console.ReadLine();
        }
    }

enter image description here

Then you can use the access token to call the Azure REST API.

Updates:

You got the error because your administrator enabled MFA. So you will not be able to use password grant flow to acquire token directly. There would be 4 workarounds:

  1. Acquire the token interactively.

  2. Use client credential to acquire a token for your application and manage resources.

  3. Acquire a token for the user for one time, and you will get a refresh token. You can use it to get new token. Refreshing the access tokens

  4. Use Joy's way. You can use managed identity.

Jack Jia
  • 5,268
  • 1
  • 12
  • 14
  • From where I can get the client id. – Abhinav Sharma Jul 12 '19 at 06:49
  • @AbhinavSharma Just use the 1950a258-227b-4e31-a9cf-717495945fc2. It is a pre-defined client from Microsoft for public. – Jack Jia Jul 12 '19 at 07:08
  • This code is not working I am getting error:-Due to a configuration change made by your administrator, or because you moved to a new location, you must enroll in multi-factor authentication to access.I have passed my clientID. – Abhinav Sharma Jul 15 '19 at 09:05
  • Secondly, I can't pass my credentials. For testing purpose, it is okay but for production who will provide their own credentials? – Abhinav Sharma Jul 15 '19 at 09:07