I am recently working on a project that requires front-end to call Azure REST APIs. Microsoft document describes how to get Access Token in postman via Jon Gallant's blog post. However, placing secret keys in front-end is very dangerous. In my project, I must get the Access Token from server side in .NET. Let's see how to do it.
Preparation
In order to get an Access Token for calling Azure REST API, you must first register an application in Azure AD as described in Microsoft document. If TLDR, you can just follow these steps for a quick start.
Go to your Azure AD, App registrations, click "New registration"
Give it a name and click "Register" to finish creating the application registration.
Go to "Certificates & secrets", click "New client secret"
In my case, I added a secret that will expires in 24 months.
Copy the Value and save it for later use. This value will display ONLY ONCE, so be sure to copy it out.
Go to the IAM of your resource that needs REST API access. In my case, it's a resource group.
Add the application registration to the resource group and give it the role you need, in my case it is "Contributor".
Get Access Token
There are many ways to get Access Token. In the official postman sample, the pre-request script will send a POST request and get the access token.
You need a client id, a tenant id, and a client secret value which we copied in previous section to get the Access Token. The other two can be copied from the application you just registered before.
pm.sendRequest({
url: 'https://login.microsoftonline.com/' + pm.collectionVariables.get("tenantId") + '/oauth2/token',
method: 'POST',
header: 'Content-Type: application/x-www-form-urlencoded',
body: {
mode: 'urlencoded',
urlencoded: [
{ key: "grant_type", value: "client_credentials", disabled: false },
{ key: "client_id", value: pm.collectionVariables.get("clientId"), disabled: false },
{ key: "client_secret", value: pm.collectionVariables.get("clientSecret"), disabled: false },
{ key: "resource", value: pm.collectionVariables.get("resource") || "https://management.azure.com/", disabled: false }
]
}
}, function (err, res) {
if (err) {
console.log(err);
} else {
let resJson = res.json();
pm.collectionVariables.set("bearerTokenExpiresOn", resJson.expires_on);
pm.collectionVariables.set("bearerToken", resJson.access_token);
}
});
In .NET, according to Microsoft, you can do it with Azure SDK for .NET libraries. But in my case, the only thing in my backend code is to return an Access Token to front-end, I don't want to use a heavy library just to use 1% of its feature. So, I decided to use the HttpClient
built in .NET to do it.
The code is just a C# translation of the above postman script.
var tenantId = "<your tenant id>";
var clientId = "<your client id>";
var secret = "<your secret>";
var resourceUrl = "https://management.azure.com/";
var requestUrl = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";
// in real world application, please use Typed HttpClient from ASP.NET Core DI
var httpClient = new HttpClient();
var dict = new Dictionary<string, string>
{
{ "grant_type", "client_credentials" },
{ "client_id", clientId },
{ "client_secret", secret },
{ "resource", resourceUrl }
};
var requestBody = new FormUrlEncodedContent(dict);
var response = await httpClient.PostAsync(requestUrl, requestBody);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
var aadToken = JsonSerializer.Deserialize<AzureADToken>(responseContent);
Console.WriteLine(aadToken?.AccessToken);
The AzureADToken
type
public class AzureADToken
{
[JsonPropertyName("token_type")]
public string TokenType { get; set; }
[JsonPropertyName("expires_in")]
public string ExpiresIn { get; set; }
[JsonPropertyName("ext_expires_in")]
public string ExtExpiresIn { get; set;
[JsonPropertyName("expires_on")]
public string ExpiresOn { get; set; }
[JsonPropertyName("not_before")]
public string NotBefore { get; set; }
public string Resource { get; set; }
[JsonPropertyName("access_token")]
public string AccessToken { get; set; }
}
Test the Access Token
Copy the token and go to postman. Try a HTTP GET request
https://management.azure.com/subscriptions/<your subscription id>/resourcegroups?api-version=2020-09-01
The token is valid and Azure REST API works fine!
Recommend Reference
To make the HttpClient
works correctly in ASP.NET Core applications, please read Use IHttpClientFactory to implement resilient HTTP requests
xavier
Hi, I follow you're tuto, but when POST my request, i have this error: "error": "invalid_request", "error_description": "AADSTS500021: Access to 'Xavier' tenant is denied.\r\nTrace ID: 8c9288e4-f718-412c-....\r\nCorrelation ID: 3769c68b-7e7f-413a-....\r\nTimestamp: 2023-04-04 08:17:59Z", "error_codes": [ 500021 ],
do you have this issue ? thanks
Megha Jain
That was really helpful. I have one query, what should be the value of "resourceUrl ". In my case , whenever a user updates any item in sharepoint list, Azure function gets triggered automatically and I need to do the authentication in azure function using access token. Can you please help here.
Brian
Just wanted to say thank you. This was easy to follow and very helpful.