Consume Dynamics 365 Web API using MSAL.NET


Sharing a sample code to consume Dynamics 365 Web API using MSAL.NET

Create a console application and add the following NuGet Package

  • Microsoft.Identity.Client

More on Microsoft identity platform

https://docs.microsoft.com/en-us/azure/active-directory/develop/

We are using ConfidentialClientApplicationBuilder create method.

https://docs.microsoft.com/en-gb/azure/active-directory/develop/msal-net-initializing-client-applications

The sample code –

using Microsoft.Identity.Client;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace CrmAppMSAL
{
class Program
{
static async Task Main(string[] args)
{

string clientId = "fc34502a-74db-4977-8c83-***********";
string secret = "5~mByJeQ8dDO2LZP_H_J2**********";
string[] scope = new string[] { "https://orgname.crm15.dynamics.com/.default" };
string webAPI = "https://[org].crm15.dynamics.com//api/data/v9.0/leads";
string authority = "https://login.microsoftonline.com/7bc93881-0733-48ab-baa1-ee3ed7717633";

var clientApp = ConfidentialClientApplicationBuilder.Create(clientId: clientId)
.WithClientSecret(clientSecret: secret)
.WithAuthority(new Uri(authority))
.Build();

try
{
AuthenticationResult authResult = await clientApp.AcquireTokenForClient(scope).ExecuteAsync();

var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);

httpClient.BaseAddress = new Uri(webAPI);

var response = httpClient.GetAsync("WhoAmI").Result;

if (response.IsSuccessStatusCode)
{
var userDetails = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(userDetails);
Console.WriteLine(authResult.AccessToken);
Console.WriteLine(authResult.ExpiresOn);
Console.ReadLine();
}

}
catch (Exception ex)
{
string errorMessage = ex.Message;
}
}
}
}

Result –

Reference –

https://medium.com/capgemini-microsoft-team/access-tokens-for-dynamics-365-using-microsoft-authentication-library-2b16c9f794b

Hope it helps..

Read Secret from Azure Key Vault using Key Vault Rest API through Postman


In the previous posts, we saw how to register an Azure AD app and read the secret from Azure Key Vault using SecretClient and UsernamePasswordCredential class

In this post, we’d fetch the secret saved in Key Vault through Postman.

  • Register an Azure AD App
  • Copy its client id and client secret
  • Provide the Get Secret permissions to the application for the Key Vault.

Within Postman we’d first fetch the token

Get the URL from endpoints

Format – https://login.microsoftonline.com/{tenantid}/oauth2/v2.0/token

Scope value – https://vault.azure.net/.default

Send the request which responds with the token.

Copy the token

Create the new Get request and pass the Secret identifier with the API version.

https://mykvcrm.vault.azure.net/secrets/MySecret/f046535ef5644ca5a4b43f2a718776b9?api-version=7.1

For authorization select type as Bearer Token and paste the token generated earlier.

Send the request to get the secret’s value as shown below – “itissecret”

Get more details here –

https://docs.microsoft.com/en-us/rest/api/keyvault/getsecrets/getsecrets

Hope it helps..

Fixed – AADSTS7000218: The request body must contain the following parameter: ‘client_assertion’ or ‘client_secret


While trying to access Azure resources using UsernamePasswordCredential credential we were getting the below error

https://docs.microsoft.com/en-us/dotnet/api/azure.identity.usernamepasswordcredential?view=azure-dotnet

Azure.Identity.AuthenticationFailedException: ‘UsernamePasswordCredential authentication failed: A configuration issue is preventing authentication – check the error message from the server for details.You can modify the configuration in the application registration portal. See https://aka.ms/msal-net-invalid-client for details. Original exception: AADSTS7000218: The request body must contain the following parameter: ‘client_assertion’ or ‘client_secret’.

Trace ID: ef6c9e2b-862a-4a8b-9519-9a9072d23301

Correlation ID: 5f9bae95-e45a-4da5-b27c-ad9704e7334e

Timestamp: 2020-11-28 05:58:05Z’

This was because Allow public client flows was disabled for the application registered in Azure AD.

Enabling it fixed the issues for us.

https://docs.microsoft.com/en-gb/azure/active-directory/develop/scenario-desktop-acquire-token?tabs=dotnet#username-and-password

More on ROPC

https://nishantrana.me/2019/08/23/connect-to-dynamics-365-web-api-using-oauth-2-0-resource-owner-password-credential-ropc/

Hope it helps..

Fixed – AADSTS65001: The user or administrator has not consented to use the application with ID


The below error occurs for the application registered with Azure AD (Delegated Permissions), which requires either user or an administrator’s consent for the permissions it needs.

“Azure.Identity.AuthenticationFailedException: ‘UsernamePasswordCredential authentication failed: AADSTS65001: The user or administrator has not consented to use the application with ID ‘9ea6c0e6-5ab5-4816-b787-5391cd41fd7b’ named ‘MyKVApp’. Send an interactive authorization request for this user and resource.”

The below setting specifies that all users can allow applications to access the organization’s data on their behalf.


Here the admin can grant the consent through the portal as shown below from Home > App > API Permissions



or can also use Consent URL

https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/grant-admin-consent#construct-the-url-for-granting-tenant-wide-admin-consent

https://login.microsoftonline.com/{tenant-id}/adminconsent?client_id={client-id}


When trying to access the consent URL using another non-admin user, we might get the below message, which means that only the admin can provide the required consent.


Signing in with the Admin account presents the below message for granting the app the required permissions.


Admin can also revoke the admin consent (along with the permission as shown below) from the portal as shown below through Remove admin consent option.


Get all the details here –

https://docs.microsoft.com/en-us/azure/active-directory/develop/application-consent-experience#consent-and-permissions

Hope it helps..


Use Azure AD Conditional Access to block access by country (Dynamics 365)


In the previous post, we covered conditional access based on the device platform, here we’d look into how we can use the network location to block the access.

We can either use IP ranges or Countries / Regions for defining the location.

Login into the Azure Portal

https://portal.azure.com/

Navigate to Azure Active Directory – Security – Named locations to define the location.


Here we are adding a new countries location record.


For the new location, we have selected India and UAE.


Next click on Conditional Access to define a new policy.


For Users and groups, we have selected a user named testuser1.


For Cloud Apps or actions, we have selected Common Data Service.


For Conditions, we have specified Locations condition with the Restricted Locations record that we had created earlier.


For Access Controls, we have selected Block access.


Enable and create the policy.


Before the policy was enabled, test user1 was able to access Dynamics 365.


After enabling the policy if we try accessing Dynamics 365 from either UAE or India location, we’d get the below message.


Same for the Dynamics 365 for Phones app.


Test user 3 to which policy doesn’t apply can still access Dynamics 365.


Hope it helps..