I have an Azure Function App (HTTP trigger function) that is protected by Azure AD authentication.
This is working fine - when I go to the URL of the function in my browser. I am first redirected to the login page where I can login using my Azure Active Directory login credentials.
However, I want the function to connect to the Dynamics 365 Web API to read some data using the identity of the logged in user. I've copied this example with regard to the code to connect to the Web API and configuring the app's permissions in Azure. My Dynamics 365 instance is in the same tenant as my Azure and the user I'm logging in with a user that has access to Dynamics 365.
The part I am struggling with is getting the access token to call Dynamics Web API that corresponds to the logged in user.
First attempt
I have then tried to use the token from the current logged in user, as per the "X-MS-TOKEN-AAD-ID-TOKEN" header. My code is as follows - it does not connect to the Dynamics Web API - I get a 401 - Unauthorized response:
[FunctionName("TestCrmFunction")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
var crmUrl = "https://myorganisation.crm11.dynamics.com";
// Get the token from the HTTP header of the request:
var token = req.Headers
.Where(x => x.Key == "X-MS-TOKEN-AAD-ID-TOKEN")
.SelectMany(x => x.Value)
.FirstOrDefault();
using (var httpClient = new HttpClient())
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
httpClient.BaseAddress = new Uri(crmUrl);
// set the token here:
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await httpClient.GetAsync("api/data/v8.1/WhoAmI");
var content = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
// I don't get here...
return req.CreateResponse(HttpStatusCode.OK, content);
}
else
{
// ... I get here
return req.CreateResponse(response.StatusCode, $"ERROR: {content}");
}
}
}
It seems that the "X-MS-TOKEN-AAD-ID-TOKEN" isn't being accepted.
Second attempt
I'm trying to get a new token for the user by creating a "UserAssertion" instance along with a ClientCredential. The UserAssertion bit I'm really not sure about and is probably wrong:
var tenantId = "<my organisation tenantID>";
var authority = $"https://login.microsoftonline.com/{tenantId}";
var authenticationContext = new AuthenticationContext(authority, false);
// create the client credential using the clientID and clientSecret:
var clientId = "<my applicationId>";
var clientSecret = "<key for my application>";
var clientCredential = new ClientCredential(clientId, clientSecret);
// create the user assertion using the access token from the authenticated user:
var accessToken = req.Headers
.Where(x => x.Key == "X-MS-TOKEN-AAD-ACCESS-TOKEN")
.SelectMany(x => x.Value)
.FirstOrDefault();
var userAssertion = new UserAssertion(
accessToken,
"urn:ietf:params:oauth:grant-type:jwt-bearer",
ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn)?.Value);
// get a new token - this step is failing
var crmUrl = "https://myorganisation.crm11.dynamics.com";
AuthenticationResult authenticationResult =
await authenticationContext.AcquireTokenAsync(crmUrl, clientCredential, userAssertion);
string token = authenticationResult.AccessToken;
The response I'm getting back is
Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: AADSTS50027: Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid.
Workaround - not a real solution
The only thing I've managed to get working is to hardcode a username/password of the user I'm logging in with:
var credentials = new UserPasswordCredential("<my username>", "<my password>");
AuthenticationResult authenticationResult = await
authenticationContext.AcquireTokenAsync(crmUrl, clientId, credentials);
... but this kind of defeats the purpose - by hardcoding a username/password, I'm surely just circumventing the Azure Application Registration security altogether?