How to use S2S Authentication to connect with Dynamics CE using Azure Functions?

1_IegFtGg3n6FiCeik2PDuhAOne of my customers requested to implement APIs which should execute some connected business logic using Dynamics CE and other Azure and non-Microsoft services. The APIs had to be publically available to access from other cloud services my customer had. To implement these requirements, we decided to use Azure Functions together with S2S Authentication. In this article, I would like to give you some examples of how to connect to Dynamics CE from Azure Functions using S2S authentication.

First of all, you need to understand and configure S2S authentication. Please check the following article to get more details: Use Single-Tenant server-to-server authentication. Once you’ve set S2S authentication for your Dynamics CE environment, you can start creating Azure Functions. Let’s first create a service function which should request Bearer Token for us. I will keep it simple without cashing or any additional logic. In a real-world scenario, you can implement caching and automatic token refresh to avoid extra service calls. By default, the token will be valid for one hour. Some more information you can find here: Configurable token lifetimes in Azure Active Directory.

public static class GetCRMBearerToken { [FunctionName("GetCRMBearerToken")] public static async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestMessage req, TraceWriter log) {
        var OrganizationUrl = "CRM Urls";
        var TenantId = "11111111-2222-3333-4444-555555555555";
        var ClientId = "11111111-2222-3333-4444-555555555555";
        var ApplicationKey = "11111111A2222A3333A4444A555555555555=";
        var httpClient = new HttpClient(); //Define the Web API base address, the max period of execute time, the // default OData version, and the default response payload format. 
        httpClient.BaseAddress = new Uri(OrganizationUrl + "api/data/");
        httpClient.Timeout = new TimeSpan(0, 2, 0);
        httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
        httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        if ((!string.IsNullOrEmpty(ApplicationKey) && !string.IsNullOrEmpty(ClientId))) {
            var clientcred = new ClientCredential(ClientId, ApplicationKey);
            var authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/" + TenantId);
            var authenticationResult = await authenticationContext.AcquireTokenAsync(OrganizationUrl, clientcred);
            return req.CreateResponse(HttpStatusCode.OK, authenticationResult.AccessToken);
        }
        return req.CreateResponse(HttpStatusCode.BadRequest, "Error");
    }
}

In the example above, I will just hardcode parameters which we need to connect to Dynamics 365. You should take these parameters from your Azure Portal during the S2S authentication process configuration. To store these settings securely, you can use Azure Key-Vault. Here you find more information about using Azure Key-Vault: Tutorial: Use Azure Key Vault with an Azure web app in .NET

The next Azure function should call Dynamics CE and extract some data from it. Here is the example which shows how to execute one azure function from another to get authentication token and extract some sample data from the Dynamics CE environment.

public static class GetContacts {
    private static Version webAPIVersion = new Version(9, 0);
    private static string getVersionedWebAPIPath() {
        return string.Format("v{0}/", webAPIVersion.ToString(2));
    } [FunctionName("GetContacts")] public static async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequestMessage req, TraceWriter log) {
        var bearerToken = await GetCRMBearerToken.Run(req, log);
        var OrganizationUrl = "https://your_org_url/"; 
//Next use a HttpClient object to connect to specified CRM Web service. 
var httpClient = new HttpClient(); //Define the Web API base address, the max period of execute time, the // default OData version, and the default response payload format. 
        httpClient.BaseAddress = new Uri(OrganizationUrl + "api/data/");
        httpClient.Timeout = new TimeSpan(0, 2, 0);
        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", ((ObjectContent) bearerToken.Content).Value.ToString());
        var queryOptions = "?$select=contactid,firstname,lastname,emailaddress1";
        HttpResponseMessage retrieveResponse = httpClient.GetAsync(getVersionedWebAPIPath() + "contacts" + queryOptions).Result;
        if (retrieveResponse.StatusCode == HttpStatusCode.OK) {
            var retrievedContacts = JsonConvert.DeserializeObject(retrieveResponse.Content.ReadAsStringAsync().Result);
            return req.CreateResponse(HttpStatusCode.OK, "OK");
        }
        return req.CreateResponse(HttpStatusCode.BadRequest, "HTTP 500 BadRequest");
    }
}

The second function uses our first function to get Bearer token and then call Web API to get data from contacts entity.

Don’t forget to add Microsoft.IdentityModel.Clients.ActiveDirectory dependency to your Azure functions project.

You can create several functions which will call different operations in CRM and return results to anonymous users. You can also configure security checks for your azure functions. More information and some examples about it you can find here: Azure Functions HTTP triggers and bindings.

I hope you got the idea of how to use S2S authentication in Azure functions and connect/extract data from your Dynamics CE organization.

Leave a Reply

Your email address will not be published. Required fields are marked *