Dynamics 365 authentication is recommended only through Azure AD (for online instances). To achieve this, first of all, we need to create an app in Azure Active Directory and the good news is that you don’t need an Azure subscription to try this out; your free trial of Dynamics 365 is enough.
The following 4 steps are involved in the implementation of this. You can always jump to the next step if you have already implemented (or you know) the current step. This topic may not be very new to everyone, but when I went to implement the same recently, it took me a few hours to make it work, perhaps because of the recent frequent Azure updates or the outdated content. This led me to write this.
- Create and configure the app in Azure Active Directory.
- Create a user in Azure AD and configure it as an application user in Dynamics 365
- Write C# code with ADAL (Active Directory Authentication Library) to generate the Access Token
- Make requests to Dynamics 365 with the above-generated Access Token
Step 1 - Create Azure AD App
Navigate to Azure (https://portal.azure.com).
On the left menu, click on Azure Active Directory -> App registrations (Preview) => + New registration. We will use the Preview version only because it has more straight-forward options and going forward, this only is going to be the default option.
Give some name to your app, and for account type, select "
Accounts in this organizational directory only" because we need it for a single tenant only.
Once the app is created, click on "API permissions" to add a new permission to your app.
Select Dynamics CRM here.
Check the user_impersonation box on the upcoming screen and click "
Add permissions".
These permissions require admin's consent. Click on the "Grant admin consent for D365In" button and confirm it. You need the administrator role to do it.
Now, your app is created. We need to use three things:
- Application Id, aka, Client Id
- Tenant Id
- Client Secret
The Application Id and Tenant Id can be grabbed from the "App Overview".
To generate the client secret, go to "Certificates & secrets" and then "+ New client secret". Give some description and select the validity of your secret. Then, click "Add".
Client Secret is something that you should keep secret; that is why you can see this only once after generation. Copy it and keep it safe to use later.
Step 2 - Create Application User
- You need to create a new user. All CRM API calls will be made on behalf of this user.
- This user does not require a Dynamics 365 license.
- This user should be created from Azure (https://portal.azure.com), not from Office Portal (https://admin.microsoft.com)
- Navigate to Azure -> Azure Active Directory -> Users and click on "+New user".
- Here, the username field must have the same domain name as your organization.
- Once this user is created, go to your Dynamics 365 instance.
- Navigate to Dynamics 365 -> Settings -> Security; click on "Users" here.
- Change the view to "Application Users" and click on "+ NEW" to create a new application user.
-
You may need to set the form also as an Application User if it’s not coming by default.
-
Here, the Application ID must be the same as Azure AD App created in the previous step. You can keep the username and email same as the one created in Azure AD. Though it’s not necessary to be the same, I have tried with the different name also. Once you save it, the Application ID URI & Azure AD Object ID will auto-populate.
- Now, you need to assign a security role to this user to perform an operation on desired records. I’ve seen in many blogs that this user must have a custom security role; so you can copy some existing role and assign it. But when I tried with OOB security role, it was still working.
Step 3 - Get Access Token with ADAL
Create a new project in Visual Studio and add the ADAL package via NuGet.
Create the below-shown method and replace the Application Id, Client Secret, Tenant Id, and your organization's URL at appropriate places.
-
- using Microsoft.IdentityModel.Clients.ActiveDirectory;
- using System.Threading.Tasks;
-
-
- public static async Task<string> AccessTokenGenerator()
- {
- string clientId = "Azure AD App Id";
- string clientSecret = "Client Secret Generated for App";
- string authority = "https://login.microsoftonline.com/< your app tenant guid >";
- string resourceUrl = "https://< your D365 org>.< crm instance location e.g crm, crm8 >.dynamics.com"; // Org URL
-
- ClientCredential credentials = new ClientCredential(clientId, clientSecret);
- var authContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(authority);
- var result = await authContext.AcquireTokenAsync(resourceUrl, credentials);
- return result.AccessToken;
- }
Step 4 - Consuming Access Token
You have the access token. Now, you can make a request to your Dynamics 365 by including this to your HTTP requests, as shown in the below method.
- public static async Task<HttpResponseMessage> CrmRequest(HttpMethod httpMethod, string requestUri, string body = null)
- {
- var accessToken = await AccessTokenGenerator();
- var client = new HttpClient();
- var msg = new HttpRequestMessage(httpMethod, requestUri);
- msg.Headers.Add("OData-MaxVersion", "4.0");
- msg.Headers.Add("OData-Version", "4.0");
- msg.Headers.Add("Prefer", "odata.include-annotations=\"*\"");
-
-
- msg.Headers.Add("Authorization", $"Bearer {accessToken}");
-
- if (body != null)
- msg.Content = new StringContent(body, UnicodeEncoding.UTF8, "application/json");
-
- return await client.SendAsync(msg);
- }
You can make different requests using the above method. Here is an example for retrieving all contacts with GET.
- var contacts = CrmRequest(
- HttpMethod.Get,
- "https://efrig.api.crm8.dynamics.com/api/data/v9.1/contacts")
- .Result.Content.ReadAsStringAsync();
Full Code (Replace your Azure credentials before executing)
- using Microsoft.IdentityModel.Clients.ActiveDirectory;
- using System.Net.Http;
- using System.Text;
- using System.Threading.Tasks;
-
- namespace D365S2S
- {
- class Program
- {
- static void Main(string[] args)
- {
- var contacts = CrmRequest(
- HttpMethod.Get,
- "https://efrig.api.crm8.dynamics.com/api/data/v9.1/contacts")
- .Result.Content.ReadAsStringAsync();
-
- }
-
- public static async Task<string> AccessTokenGenerator()
- {
- string clientId = "13950f0e-0000-4e2f-0000-b923302c4338";
- string clientSecret = "0^C#%0000DR7/#Z[-.m5aYO00000000$";
- string authority = "https://login.microsoftonline.com/ceb48f70-0000-1111-0000-9170f6a706a6"; // Azure AD App Tenant ID
- string resourceUrl = "https://efrig.crm8.dynamics.com"; // Your Dynamics 365 Organization URL
-
- var credentials = new ClientCredential(clientId, clientSecret);
- var authContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(authority);
- var result = await authContext.AcquireTokenAsync(resourceUrl, credentials);
- return result.AccessToken;
- }
-
- public static async Task<HttpResponseMessage> CrmRequest(HttpMethod httpMethod, string requestUri, string body = null)
- {
-
- var accessToken = await AccessTokenGenerator();
-
- var client = new HttpClient();
- var message = new HttpRequestMessage(httpMethod, requestUri);
-
-
- message.Headers.Add("OData-MaxVersion", "4.0");
- message.Headers.Add("OData-Version", "4.0");
- message.Headers.Add("Prefer", "odata.include-annotations=\"*\"");
-
-
- message.Headers.Add("Authorization", $"Bearer {accessToken}");
-
-
- if (body != null)
- message.Content = new StringContent(body, UnicodeEncoding.UTF8, "application/json");
-
- return await client.SendAsync(message);
- }
- }
- }
I hope it helps. Feel free to get in touch for any query or suggestion.