Search code examples
c#azureoauthdynamics-crmdynamics-crm-2016

Dynamics CRM web api 401 Unauthorized after obtaining Oauth token


I am having trouble making an HTTP GET request to our Dynamics CRM 2016 web API for a proof-of-concept.

I have followed this walk-through to create a multi-tenant web app set up on Azure Active Directory, which has been granted access to Dynamics CRM as an organisation user.

I used this example code in order to obtain an access token. This appears to work, providing me with what looks like a valid token.

I do a simple GET request using the token, which fails with a 401 Unauthorized. The code:

class Test
{
    public async Task RunAsync()
    {
        var resource = "https://<snip>.crm4.dynamics.com/api/data/v8.1/";
        var authParams = AuthenticationParameters.CreateFromResourceUrlAsync(new Uri(resource))
            .Result;
        var authorityUrl = authParams.Authority;
        var resourceUrl = authParams.Resource;

        var clientId = "<snip>";
        var client_secret = "<snip>";
        var clientCredential = new ClientCredential(clientId, client_secret);

        var authContext = new AuthenticationContext(authorityUrl, false);
        var token = authContext.AcquireToken(resourceUrl, clientCredential);

        var response = await CallApiAsync($"{resourceUrl}api/data/v8.1/accounts?$select=name&$top=3", token.AccessToken);
        var content = await response.Content.ReadAsStringAsync();

        Console.WriteLine(response.RequestMessage);
        Console.WriteLine(response.Headers);
        Console.WriteLine(response.ReasonPhrase);
        Console.WriteLine(content);
    }

    private async Task<HttpResponseMessage> CallApiAsync(string uri, string token)
    {
        using (var httpClient = new HttpClient())
        {
            httpClient.DefaultRequestHeaders.Authorization =
                new AuthenticationHeaderValue("Bearer", token);
            httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
            httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
            httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");

            return await httpClient.GetAsync(uri);
        }
    }
}

The request:

Method: GET, RequestUri: 'https://<snip>.crm4.dynamics.com/api/data/v8.1/accounts?$select=name&$top=3', Version: 1.1, Content: <null>, Headers:
{
  Authorization: Bearer <snip>
  Accept: application/json
  OData-MaxVersion: 4.0
  OData-Version: 4.0
} 

Response:

REQ_ID: <snip>
Strict-Transport-Security: max-age=31536000; includeSubDomains
Date: Tue, 21 Feb 2017 15:08:39 GMT
Set-Cookie: crmf5cookie=<snip>;secure; path=/
Server: Microsoft-IIS/8.5
WWW-Authenticate: Bearer authorization_uri=https://login.windows.net/<snip>/oauth2/authorize,resource_id=https://<snip>.crm4.dynamics.com/
X-Powered-By: ASP.NET

Unauthorized
HTTP Error 401 - Unauthorized: Access is denied

I feel like I'm missing something obvious?


Solution

  • There is no CRM organization user being used. Check out this Server to Server Auth tutorial. You'll need to create an application user. There is a little more commentary here on the Tip of the Day for Server to Server Auth.

    Outside of Server to Server Auth you can authenticate as a CRM user using creds this way.