Connecting to D365

In Dynamics 365 with O365 authentication (WS-Trust) being deprecated, following are the available options to query Dynamics 365 data using SDK.

We can use CrmServiceClient with WebAPI/Organization Service or directly call WebAPI. Following are possible ways:

  • Certificate
  • OAuth
  • ClientSecret
  1. We need to register app on Azure AD and then create client secret/Certificate.

You can navigate to Azure AD and go to ‘App Registrations’ and then create a new app. Follow the steps as per here :

https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/walkthrough-register-app-azure-active-directory#create-an-application-registration

2. To add Client Secret to the newly created App, please follow below steps :

https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app#add-a-certificate

https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app#add-a-client-secret

To use certificate authentication – Create Self Signed Certificate (if you don’t have it already) and Upload Certificate or install the certificate on your local.

3. Register the App user in Dynamics 365 with App client ID and give proper role.

Authentication with Certificate comparison

Authentication with OAuth comparison

Certificate Authentication

HTTP Body

Certificate with CrmServiceClient (Organization Service)
private static void CertificateCreate()
 {
     string ConnectionStringCertificate = @"AuthType = Certificate;SkipDiscovery=true;Url = https://[orgname].crm.dynamics.com;thumbprint = [ThumbPrint];ClientId = [ClientId];";
     CrmServiceClient svc = new CrmServiceClient(ConnectionStringCertificate);
     var res = svc.Create(new Microsoft.Xrm.Sdk.Entity("contact")
     {
        Attributes = new Microsoft.Xrm.Sdk.AttributeCollection
        {
           new KeyValuePair("firstname","testuserOCertificate"),
           new KeyValuePair("lastname","CrmServiceClient"),
        }
     });
     Console.WriteLine("Certificate Record ID :" + res.ToString());
 }
Certificate with CrmServiceClient (WebAPI)
public static void OAuthCertificateCreate()
 {
     string ConnectionStringOAuth = @"AuthType = Certificate;SkipDiscovery=true;Url = https://[orgname].crm.dynamics.com;thumbprint = [ThumbPrint];ClientId = [ClientId];";
     CrmServiceClient svc = new CrmServiceClient(ConnectionStringOAuth);
     Dictionary> odataHeaders = new Dictionary>
     {
        { "Accept", new List () { "application/json" } },
        { "OData-MaxVersion", new List () { "4.0" } },
        { "OData-Version", new List () { "4.0" } }
     };
     if (svc.IsReady)
     {
        dynamic contact = new { firstname = "testuserWebAPI", lastname = "CrmServiceClient" };
        string jsonContact = JsonSerializer.Serialize(contact);
        HttpResponseMessage httpResponse = svc.ExecuteCrmWebRequest(
        HttpMethod.Post,
        "contacts",
        jsonContact,
        odataHeaders,
        "application/json");
       if (httpResponse.IsSuccessStatusCode)
      {   
          var contactUri = httpResponse.Headers.GetValues("OData-EntityId").FirstOrDefault();
          Console.WriteLine("OAuth Record ID : {0}", contactUri.Split('(').Last().Split(')').First());
      }
      else
      {   
          Console.WriteLine(httpResponse.ReasonPhrase);
      }
    }
}
Certificate without CrmServiceClient (WebAPI)
private static void CertificateWebAPICreate()
 {
     string clientId = "[ClientId]";
     string url = "https://[orgname].crm.dynamics.com";
     var userCredential = new UserPasswordCredential("[username]@[tenant].onmicrosoft.com", "[Password]");
     string apiVersion = "9.1";
     string webApiUrl = $"{url}/api/data/v{apiVersion}/";
     var authParameters = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(webApiUrl)).Result;
     var authContext = new AuthenticationContext(authParameters.Authority, false);
     ClientAssertionCertificate cl = new ClientAssertionCertificate(clientId, new X509Certificate2(@"C:\d365cert-D365Login-20201126.pfx", "[certificate password]"));
     var authResult = authContext.AcquireTokenAsync(url, cl).GetAwaiter().GetResult();
     var authHeader = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
     using (var client = new HttpClient())
     {
         client.BaseAddress = new Uri(webApiUrl);
         client.DefaultRequestHeaders.Authorization = authHeader;
         JObject contact1 = JObject.Parse(@" 
         {firstname: 'testuserWebAPI', 
         lastname: 'certificate' " + @"}");
         HttpRequestMessage createrequest1 = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress + "contacts");
         createrequest1.Content = new StringContent(contact1.ToString());
         createrequest1.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
         HttpResponseMessage createResponse1 = client.SendAsync(createrequest1, HttpCompletionOption.ResponseHeadersRead).Result;
         if (createResponse1.IsSuccessStatusCode)
         {
               var id = createResponse1.Headers.GetValues("OData-EntityId").First().Split('(').Last().Split(')').First();
               Console.WriteLine("Certificate WebAPI Record ID : {0}", id);
         }
         else
        {
               Console.WriteLine("The request failed with a status of '{0}'",createResponse1.ReasonPhrase);  
        } 
   }
}

OAuth Authentication

HTTP Body

OAuth with CrmServiceClient (Organization Service)
public static void OAuthOrganizationServiceCreate()
 {
     string ConnectionStringOAuth = @"AuthType = OAuth;
     Username = [username]@[tenant].onmicrosoft.com;
     Password = [Password];
     Integrated Security=true;
     Url = https://[orgname].crm.dynamics.com;
     AppId = [ClientId];
     RedirectUri = https://redirectURL;
     LoginPrompt=Auto";
     CrmServiceClient svc = new CrmServiceClient(ConnectionStringOAuth);
     var res = svc.Create(new Microsoft.Xrm.Sdk.Entity("contact")
     {
        Attributes = new Microsoft.Xrm.Sdk.AttributeCollection
        {
          new KeyValuePair("firstname","testuserOrganizationService"),
          new KeyValuePair("lastname","CrmServiceClient"),
        }
     });
     Console.WriteLine("OrganizationService OAuth Record ID : {0}", res.ToString());
 }
OAuth with CrmServiceClient (WebAPI)
public static void OAuthCreate()
 {
     string ConnectionStringOAuth = @"AuthType = OAuth;
     Username = [username]@[tenant].onmicrosoft.com;
     Password = [Password];
     Integrated Security=true;
     Url = https://[orgname].crm.dynamics.com;
     AppId = [ClientId];
     RedirectUri = https://redirectURL;
     LoginPrompt=Auto";
     CrmServiceClient svc = new CrmServiceClient(ConnectionStringOAuth);
     Dictionary> odataHeaders = new Dictionary>
     {
       { "Accept", new List () { "application/json" } },
       { "OData-MaxVersion", new List () { "4.0" } },
       { "OData-Version", new List () { "4.0" } }
     };
     if (svc.IsReady)
     {
       dynamic contact = new { firstname = "testuserWebAPI", lastname = "CrmServiceClient" };
       string jsonContact = JsonSerializer.Serialize(contact);
       HttpResponseMessage httpResponse = svc.ExecuteCrmWebRequest(
       HttpMethod.Post,
       "contacts",
       jsonContact,
       odataHeaders,
       "application/json");
 
      if (httpResponse.IsSuccessStatusCode)
      {    
          var contactUri = httpResponse.Headers.GetValues("OData-EntityId").FirstOrDefault();     
          Console.WriteLine("OAuth Record ID : {0}", contactUri.Split('(').Last().Split(')').First());     
       }     
       else   
       {    
           Console.WriteLine(httpResponse.ReasonPhrase);  
       }    
   }
}
OAuth without CrmServiceClient (WebAPI)
public static void WebAPICreate()
 {
    string clientId = "[ClientId]";
    string url = "https://[orgname].crm.dynamics.com";
    var userCredential = new UserPasswordCredential("[username]@[tenant].onmicrosoft.com", "[Password]");
    string apiVersion = "9.1";
    string webApiUrl = $"{url}/api/data/v{apiVersion}/";
    var authParameters = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(webApiUrl)).Result;
    var authContext = new AuthenticationContext(authParameters.Authority, false);
    var authResult = authContext.AcquireTokenAsync(url, clientId, userCredential).GetAwaiter().GetResult();
    var authHeader = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
 using (var client = new HttpClient())
    {
      client.BaseAddress = new Uri(webApiUrl);
      client.DefaultRequestHeaders.Authorization = authHeader;
      JObject contact = JObject.Parse(@"{firstname: 'testuserOrganizationService', lastname: 'OAuth' " + @"}");
      HttpRequestMessage createrequest1 = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress + "contacts");
      createrequest1.Content = new StringContent(contact.ToString());
      createrequest1.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
      HttpResponseMessage createResponse1 = client.SendAsync(createrequest1, HttpCompletionOption.ResponseHeadersRead).Result;
      if (createResponse1.IsSuccessStatusCode)
      {
        var id = createResponse1.Headers.GetValues("OData-EntityId").First().Split('(').Last();
        Console.WriteLine("WebAPI Record ID {0}", id);
      }
      else
      {
        Console.WriteLine("The request failed with a status of '{0}'", createResponse1.ReasonPhrase);
      }
    }
 }

Client Secret Authentication

HTTP Body

ClientSecret with CrmServiceClient (Organization Service)
public static void ClientSecretOrganizationServiceCreate()
 {
    string ConnectionStringClientSecret = @"AuthType = ClientSecret;
         Url = https://[orgname].crm.dynamics.com;
         AppId = [ClientId];
         ClientSecret = [ClientSecret]";
    CrmServiceClient svc = new CrmServiceClient(ConnectionStringClientSecret);
    var res = svc.Create(new Microsoft.Xrm.Sdk.Entity("contact")
    {
        Attributes = new Microsoft.Xrm.Sdk.AttributeCollection
        {
           new KeyValuePair("firstname","testuserClientSecret"),
           new KeyValuePair("lastname","CrmServiceClient"),
        }
    });
    Console.WriteLine("ClientSecret Record ID :" + res.ToString());
 }
ClientSecret with CrmServiceClient (WebAPI – NOT ALLOWED)
public static void OAuthCClientSecretCreate()
 {
     string ConnectionStringOAuth = @"AuthType = ClientSecret;
                       Url = https://[orgname].crm.dynamics.com;
                       AppId = [ClientId];
                       ClientSecret = [ClientSecret]";
    CrmServiceClient svc = new CrmServiceClient(ConnectionStringOAuth);   
    Dictionary<string, List<string>> odataHeaders = new Dictionary<string, List<string>> {
     { "Accept", new List<string> () { "application/json" } },
     { "OData-MaxVersion", new List<string> () { "4.0" } },
     { "OData-Version", new List<string> () { "4.0" } }     
    };
    if (svc.IsReady) 
    {
       dynamic contact = new { firstname = "testuserClientSecret", lastname = "CrmServiceClient" };
       string jsonContact = JsonSerializer.Serialize(contact);
       try
      {
         HttpResponseMessage httpResponse = svc.ExecuteCrmWebRequest(
             HttpMethod.Post,
             "contacts",
             jsonContact,
             odataHeaders,
             "application/json");
         if (httpResponse.IsSuccessStatusCode)
         {
             var contactUri = httpResponse.Headers.GetValues("OData-EntityId").FirstOrDefault();
             Console.WriteLine("OAuth Record ID : {0}", contactUri.Split('(').Last().Split(')').First());
         }
         else
         {
             Console.WriteLine(httpResponse.ReasonPhrase);
         }
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.Message);
     }
 }
}

  Error: Cannot utilize WebAPI for this request, only oAuth or certificate type authentication is supported 

%d bloggers like this: