I'm trying to access a Dynamics CRM Online REST API with Azure AD oAuth 2 Authentication. In order to do so I followed these steps:
- I've registered a web application and/or web api in Azure
- Configured the permissions to Dynamics CRM to have Delegated permissions "Access CRM Online as organization user"
- And created a Key with a 1 year expiration and kept the Client ID generated.
After the web app was configured on Azure I have created a Console application in .NET/C# that uses ADAL to make a simple request, in this case to retrieve a list of accounts:
class Program
{
private static string ApiBaseUrl = "https://xxxxx.api.crm4.dynamics.com/";
private static string ApiUrl = "https://xxxxx.api.crm4.dynamics.com/api/data/v8.1/";
private static string ClientId = "2a5dcdaf-2036-4391-a3e5-9d0852ffe3f2";
private static string AppKey = "symCaAYpYqhiMK2Gh+E1LUlfxbMy5X1sJ0/ugzM+ur0=";
static void Main(string[] args)
{
AuthenticationParameters ap = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(ApiUrl)).Result;
var clientCredential = new ClientCredential(ClientId, AppKey);
var authenticationContext = new AuthenticationContext(ap.Authority);
var authenticationResult = authenticationContext.AcquireToken(ApiBaseUrl, clientCredential);
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authenticationResult.AccessToken);
var result = httpClient.GetAsync(Path.Combine(ApiUrl, "accounts")).Result;
}
}
I retrieve an access token successfully but when I try to do a httprequest to CRM I always get a 401 - Unauthorized status code. What am I missing?
1 year and 2 months later, this same code works perfectly. As many have stated, Dynamics 365 started to support Server-to-Server (S2S) authentication in the meantime. The only step that I had to make that I didn't back then was to create an application user. For more information about how to make this authentication work check this website: https://msdn.microsoft.com/en-us/library/mt790170.aspx
Thanks everyone for your answers. I finally managed to access Dynamics CRM OData API using ADAL 3.
Since many people are still having problems doing this, see the following steps:
Log into portal.azure.com
using your Office 365 administrator user of your Dynamics CRM subscription.
Go to Azure Active Director\App registrations and add New application registrations
Enter "Name" and "Sign-on URL", the URL could be anything (https://localhost for example)
Select the registered app you just created, go to Settings\Keys
Enter a key description, click Save and copy the Value (and keep it since you will need it later). Also copy the Application ID of the registered app.
Go to "Required Permissions", click Add, select "Dynamics CRM Online" then tick "Access CRM Online as organisation users".
These steps enable a client application to access Dynamics CRM by using the Application ID and the client secret you created in step 5. Your client application is now able to be authenticated against Azure AD with permission to access CRM Online. However, CRM Online does not know about this "client application" or "user". CRM API will response a 401 if you try to access it.
To let CRM know about the "client application" or "user", you'll need to add an application user.
Go to CRM\Security Roles, create a new Security Role or just copy the "System Administrator" Role
Go to CRM\Settings\Security\Users, create a new User, change the form to "Application User"
Enter the required fields with the Application ID that you have in previous step. Once saved, CRM will auto populate the Azure AD Object ID and the URI.
Add the user to the Security Role created from previous step.
Now you should be able to access CRM API using HttpClient and ADAL using the sample code below:
var ap = await AuthenticationParameters.CreateFromResourceUrlAsync(
new Uri("https://*****.api.crm6.dynamics.com/api/data/v9.0/"));
String authorityUrl = ap.Authority;
String resourceUrl = ap.Resource;
var authContext = new AuthenticationContext(authorityUrl);
var clientCred = new ClientCredential("Application ID", "Client Secret");
var test = await authContext.AcquireTokenAsync(resourceUrl, clientCred);
Console.WriteLine(test.AccessToken);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", test.AccessToken);
var response = await client.GetAsync("https://*****.api.crm6.dynamics.com/api/data/v9.0/contacts");
var contacts = await response.Content.ReadAsStringAsync();
Console.WriteLine(contacts);
}
I'd advise you to have a look at Server-to-Server (S2S) authentication, which was added to Dynamics 365 in the latest release.
By using S2S you do not need a paid Dynamics 365 license. Rather than user credentials, the application is authenticated based on a service principal identified by an Azure AD Object ID value which is stored in the Dynamics 365 application user record.
More information can be found here: https://msdn.microsoft.com/en-us/library/mt790168.aspx https://msdn.microsoft.com/en-us/library/mt790170.aspx
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With