Dynamics 365 Online S2S Authentication - Full Explain

Server-to-Server (S2S) authentication (only support Dynamics 365 online) was great, it use ClientId/SecretKey to authentication (instead use UserName/Password) and it use without Dynamics 365 license.

But everybody have problem when use CllientId/SecretKey, the main problem is HTTP Error 401 - Unauthorized: Access is denied

I headache this problem more than 3 days, and now, I succeed authentication with ClientId/SecretKey.

This post I will fully explain you how I can achieve it.

Important noted: do the correct order step by step here

1. Register App with Azure Active Directory

After you register App, save these value here to use it later

  • Application ID
  • Url redirect
  • SecretKey

Application ID

Save Application ID

Redirect URI

Save Redirect URI


Save SecretKey. Rember the SecretKey only show once.

When register App use Application Type = Native and Assign Permission to Dynamics CRM Online

2. Create new Office365 user

We call this user as ApplicationUser

  • Assign CRM Online license
  • Role: Dynamics 365 Service Administrator


Create new Office 365 user with Dynamics 365 license and role

3. Create a custom security role and assgin to ApplicationUser

Open Dynamics 365 by CRM Administrator account

  • Clone a System Administrator security role to new ApplicationUserRole
  • Assign ApplicationUserRole to ApplicationUser user


Clone System Administrator role to ApplicationUserRole

Assign ApplicationUserRole

Assign ApplicationUserRole to ApplicationUser

  • Open Application User form for this ApplicationUser

    • Change form from User to Application User (if not change)
    • Update field Application ID from step 1.a (Application ID)
    • Save and go back to Enabled Users

    Update Application ID

    Update Application ID for ApplicationUser

  • Change view to Application Users and check field Application ID URI for ApplicationUser empty

Application ID URI Empty

Make sure Application ID URI of ApplicationUser is emtpy

4. Remove Dyanmics 365 license

Back to 365 admin and remove Dynamics CRM license from ApplicationUser you already do in step 2 Remove License

S2S Authentication no need a license, if you assign license to ApplicationUser it not work.

5. Manually build url and use it once

The syntax url here


  • talent-id: your azure active directory id. Azure portal -> Azure Active Directory -> Properties -> Directory ID talent-id
  • application-id: step 1.a
  • url-redirect: step 1.b
  • crm-ur: your full Dynamics 365 url, E.g.: https://abcd.crm.dynamics.com
  • new-guid: generator a new GUID

My final manually url here:


6. Grant ApplicationUser to App

  • Use the manually url build on step 5. Open IE private window and paste the url to IE address bar
  • Process first time login (and only do it once) with the ApplicationUser you create in step 2, it redirect to url-redirect. Leave it and close your IE browser.

Grant permission to ApplicationUser

First and only once login to grant permission to ApplicationUser

7. Check Application ID URI

Goback to Application Users view and check the Application ID URI (step 3.e.1) now have value same value with Applcation ID

The key I found here, if this field NULL, 401 return.

ApplicationUser with Application ID URI

8. Build console application

  • Create a console application
  • Use code below and now you can see WhoAmI

Note: you can use authenticationResult.AccessToken for WebAPI call in the header request

class Program
    static private Uri GetServiceUrl(string organizationUrl)
        return new Uri(organizationUrl + @"/xrmservices/2011/organization.svc/web?SdkClientVersion=8.2");
    static void Main(string[] args)
        var organizationUrl = "https://phuoc2017mar26.crm.dynamics.com";
        var aadInstance = "https://login.microsoftonline.com/";
        var tenantID = "12b5c856-99c8-4268-b99f-b5bfd02ae0f3";
        var clientId = "2015d711-986e-4728-87d5-228994e190ba";
        var appKey = "your-private-secret-key-here";
        var clientcred = new ClientCredential(clientId, appKey);
        var authenticationContext = new AuthenticationContext(aadInstance + tenantID);
        var authenticationResult = authenticationContext.AcquireToken(organizationUrl, clientcred);
        var requestedToken = authenticationResult.AccessToken;
        using (var sdkService = new OrganizationWebProxyClient(GetServiceUrl(organizationUrl), false))
            sdkService.HeaderToken = requestedToken;
            var request = new OrganizationRequest()
                RequestName = "WhoAmI"
            var response = sdkService.Execute(new WhoAmIRequest()) as WhoAmIResponse;

Run the code and I get the result here


I get UserID GUID of ApplicationUser we already grant permission to App


Some mistakes

  • Don’t assign Application ID to user.
  • Don’t create a custom security role and assign to application user, everybody always use default System Administrator role and assign to application user.
  • Build correct url above but login with another user that have assign Application ID, or login with user don’t assign application key
  • Forgot remove license from user before use url above.
  • Manually url not match with url-redirect when register application in Azure Active Directory
  • Don’t do correct order I list here

Finally your target

  • Application User should in Application Users view
  • Application User should have 3 field (not blank)
    • Application ID
    • Application ID URI
    • Azure AD Object ID
  • Application User should remove Dynamics 365 license
  • Application User must have a custom security role

Hope this post working for you.