This post demonstrates one way of obtaining an OAuth access token from Dynamics 365 CRM and it is one of the very first steps in building external applications using the Web API. You can refer to this post if you have any other Microsoft OData-based endpoints in Azure that you want to interact with such as Microsoft Graph, Microsoft SharePoint Online.
I usually like to start my post with the why but not the how. This is because I like to understand the reason behind using a certain technology for my scenario. Understanding the what and why help you investigate, debug and fix when things go wrong. Sometimes things just work doesn’t mean they work reliably.
Let’s have a look at what you can take home after you finish (or partially finish) the reading.
Table of contents
- The why
- A quick intro to OAuth in Azure
- The how
- A quick note on using Azure Active Directory Endpoint (V1)
The why
Back to the early days of CRM, the only option we had to interact with CRM endpoint from a .NET application was to use the SDK. This SDK has been designed to allow us perform CRUD operations on entities through a SOAP service, called Organization Service. We also use it to build plugins and workflows for CRM. Unfortunately, this only worked in the full .NET framework. When the .NET Core was born, things started to change along side with the introduction of Dynamics 365 CRM online. Microsoft introduced an OData-based API for CRM, namely Web API. This is the REST version, which means we can interact from both the front end (Javascript) and back end code (C# or any other programming languages). This makes it so much easier for us to build apps for CRM, especially when using the modern .NET Core.
.NET Core is cross-platform and a lightweight version of the full .NET so we should use it when possible.
A quick intro to OAuth in Azure
If you landed at this page, I would’ve assumed that you had some idea on OAuth protocol. CRM Web API fully utilizes this protocol to grant access to the requested resources based on permissions given.
Authorizing access to CRM Web API is performed based on one of the following OAuth grant types:
- Authorization Code
- Client Credentials
- Refresh Token
- Legacy: Implicit Flow
- Legacy: Password Grant
Each grant type is designed for a different use case. For instance, a SPA may need access to CRM endpoint via a back end API, in this case, implicit flow is suitable. The back end API wants to talk to CRM, Authorization Code, Client Credentials or Password Grant can be applied.
When trying to obtain an access token from CRM endpoint, there are two things you need to distinguish:
- Obtaining the token from Azure Active Directory Endpoint (V1) or,
- Obtaining the token from Microsoft Identity Platform Endpoint (V2)
These 2 versions are very different. V1 uses something called resource-based while V2 is a scope-based. Apps registered in Azure are configured to use V2 endpoints by default but you can switch to V1 through the Manifest file. You can also specify the endpoints you want to call in the client code.
The how
Most external applications built for CRM interact with the endpoint through a non interactive user called application user (see this link for more information on this topic). This is how we grant permissions to the client app and it’s specific to CRM. Other endpoints may not have this machinism (such as Microsoft Graph). If this occurs to you then you’ll need to configure through the App Registration Portal.
We’ll be using Authorization Code grant type to get access to CRM endpoint using the V2 version. When working with the client app, it will be the concept to keep in mind when writing the client code to retrieve the token. For instance, we use ADAL.NET to deal with V1 and MSAL.NET for V2. I’ll quickly cover V1 at the end of this post.
The process of obtaining a token involves:
- Registering the client in Azure portal
- Creating an application user in CRM and link it to the app registered in Azure
- Acquiring the token from a client (I’ll be using C# within a .NET Core app)
Register the application with an Azure AD tenant
Let’s navigate to Azure portal and register the client:
- Supported account types: the type of Microsoft User Account you want to authenticate with the Azure V1 or V2. I use the first option (for a work account) but to be honest, we are using a non-interactive user in CRM so this isn’t a big deal. You’ll understand why as you’re reading through this post.
- Redirect URI (optional): This is the callback URL that Microsoft uses to give the token back. If you are using implicit flow, this is a must as the token is embedded in the URL returned after the authorization is successful. For authorization code grant flow, the code is sent back to this url which we can then use to request the token.
Clicking on Register brings you to to Overview tab:
Please take a note on the Application ID, and Directory ID, we’ll need them later in this post.
Another thing you want to pay attention to is the Endpoints. These are authorization endpoints for V1 and V2 I mentioned earlier.
We are using V2 version so take a copy of these:
- https://login.microsoftonline.com/your-tenaint-guid/oauth2/v2.0/authorize
- https://login.microsoftonline.com/your-tenaint-guid/oauth2/v2.0/token
API permissions
Here you can define permissions to any other API such Microsoft Graph, Microsoft SharePoint online. You can also grant permissions to your own APIs.
We are going to give permission to our CRM endpoint.
Select Dynamics CRM and click Add permissions.
Have a closer look on the scope url for CRM API and take a copy of it.
Create a client secret key
Every app registered in the App Registration portal needs a secret key so let’s create one and take a copy of it.
Create an application user in CRM
Let’s go to our Dynamics CRM instance and create an application user. We’re going to give this user a role to interact with entities in CRM. This is how we authorize access to CRM and it’s the reason why we don’t define scopes in the App Registration portal.
https://your-instance.crm6.dynamics.com/ => Settings => Security => Users
Select User: Application User form:
We enter the Application ID we copied from the App Registration previously.
The other fields are just a presentation thing. For example, the full name, you want this name to be meaningful because when an record is created or updated in CRM, this user will be marked in the createdby or modifedby field.
Here we define where the actual access token can be used for. We do this by giving this user a role. For a quick test, we use System Admin role but for a production environment, you may want to define a set of permissions such as Sales Role, Support Role, etc. then assign those roles to the user, so it can only CRUD within those scopes.
Acquire the token from a client app
Because we are using authorization code flow, this process involves 2 steps:
- Acquiring the authorization code
- Using this authorization code to request a CRM access token
Request an authorization code
Endpoint: https://login.microsoftonline.com/your-tenaint-guid/oauth2/v2.0/authorize
Enter this url into your browser, replace the query string parameters with your tenant and client information.
https://login.microsoftonline.com/your-tenaint-guid/oauth2/v2.0/authorize?
client_id=your_client_guid
&response_type=code
&redirect_uri=http://localhost:44306
&response_mode=query
&scope=https://your-instance.crm6.dynamics.com/user_impersonation
&state=12345
client_id
is the Application ID we retrieved previouslyresponse_type
is the authorization code (remember we are using authorization code grant flow here)scope
is the url we retrieved previously from the API permission section. The reason why I want to talk about this parameter is because we are using our CRM instance, not theadmin.services.crm
so please replace with your instance url.#From https://admin.services.crm.dynamics.com/user_impersonation #To https://your-instance.crm6.dynamics.com/user_impersonation
response_mode
is the format we want to see the token. Query means we want the token to be embedded in the url.
Take a copy of this code
value.
http://localhost:44306/?code=OAQABAAIAAAAm-............-COgvcpznyAA
&state=12345
&session_state=2dbd8e2e-58a9-4219-a765-7bfb0d4eb847
Request an access token
Weed need to send a POST request to the token endpoint we copied earlier.
Endpoint: https://login.microsoftonline.com/your-tenant-guid/oauth2/v2.0/token
POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=76dc2d83-.....-d779ae4db8e4
&scope=https://your-instance.crm6.dynamics.com/user_impersonation
&code=OAQABAAIAAAAm-............-COgvcpznyAA
&redirect_uri=http://localhost:44306
&grant_type=authorization_code
&client_secret=JqQX2PNo9bpM0uEihUPzyrh
Using Postman makes it easier for use to send our HTTP post request and test the token.
The token returned is a Bearer type. You can see a readable version using https://jwt.io/
A quick note on using Azure Active Directory Endpoint (V1)
Obtaining tokens from V1 endpoints is done in the same way as V2. The only differences are the endpoints and the query parameters.
To learn how you can obtain the token from a C# application, please refer to my post on building a sync job for CRM. In that post, I used ADAL.NET against V1 endpoints.
Request an authorization code
Endpoint: https://login.microsoftonline.com/your-tenaint-guid/oauth2/v2.0/authorize
https://login.microsoftonline.com/your-tenant-guid/oauth2/authorize?
response_type=code
&prompt=login
&redirect_uri=http://localhost:44306
&client_id=76dc2d83-.....-d779ae4db8e4
Request an access token
Endpoint: https://login.microsoftonline.com/your-tenant-guid/oauth2/token
POST /{tenant}/oauth2/token HTTP/1.1
Host: https://login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=76dc2d83-.............ae4db8e4
&resource=https://your-instance.crm6.dynamics.com
&code=OAQABAAIAAAAm-............-COgvcpznyAA
&redirect_uri=http://localhost:44306
&grant_type=authorization_code
&client_secret=JqQX2P....pM0uEihUPzyrh
Thankѕ for the marveⅼous postіng! І truly enjoyed reading іt, you happen to be a great auth᧐r.
I wіll maкe certain to bookmark your bloɡ and will come back sometіme
soon. I want to encourage you tο сontinue your great posts,
hаve a nice morning!
Thanks for your comment, it’s been a long time since my last post but I’m coming back to it now. I’m currently writing a post regarding CRM topic. This will make the job of querying CRM data a lot easier. Stay tuned. :))
Ƭhis web site really has all of the informatiߋn and facts I
needed concerning this subject and didn’t know who to ask.
Ӏ’m gone to convey my little brother, that he should also go to see this website on reɡular basis to get updated from newest gossip.
I haven’t enabled subscription feature on my blog as I received a lot of spam emails in the past but should you need to find out more information, please visit my blog. I know I haven’t posted for quite a while but I’m coming to it now.