Search This Blog

Sunday, June 25, 2023

Using Power Automate to trigger on Create or Update in the CDS and make HTTP requests with OAuth 2.0 authentication

 Background to the flow

The background to this flow is that there was a requirement which was to be solved by using an API which someone else had created, I simply needed to make an HTTP request sending in some data from the CDS, using OAuth 2.0 authentication. I decided to go with a flow. It seamed like a simple task but actually it got me pulling my hair out before I got it to work. Fortunately, I do enjoy problem solving and I keep on trying until things work. All the time. It is almost like an obsession.

Summary of the flow  

The flow triggers when a record of the Account entity is created or updated (updated with certain information, I have a triggering attribute configured). It then checks if this triggering attribute has a certain value and if yes continues. It also verifies that the values that I am supposed to send with the request actually exists. A HTTP request is then made in order to get an access token, then a new HTTP request is made, where the token is used and I send in some information from the CDS (Organisation Number and the GUID for the Account).

Later I will also add actions to the flow so that the response from the HTTP request (status code and user friendly message) is saved to the record in the CDS. But I will let that part be out of scope for this blog post.

Using Power Automate to send an HTTP request to notify that a new customer has been created (or updated)

Building up the flow

The first step is to make the flow trigger when a record is created or updated in the CDS, in this case when an Account is created or a certain field is updated. Go to the maker portal make.powerapps.com and choose to create a new flow. I would recommend to start from a Solution.

Choose the Common Data Service (Current Environment). Choose the entity of your choice, i.e. for which entity the flow should trigger, in my case the Account entity. Choose scope organization if it should apply for everyone. We only want to trigger the flow when we actually need to trigger it, not every time an Account record is updated, rather when a certain field is updated. That is why we should also choose filtering attribute/s.

Common Data Service (Current Environment) – Trigger the flow when Accounts (“Konton” in Swedish) are created and when the field cc_customer_type is updated

Then I create a variable. Just to make the flow easier to read and follow if something needs to be verified in the run flow. Here I am actually a bit confused if I should use a variable as action or a Compose action. Please feel free to make a comment to this blog post if you have some clever thoughts about it. Take a look at the Access Token of the flow. There I use a Compose action. As I understand Compose actions are set and can never be changed, which means I could use that for Customer Type since I only want this in order to make the flow easier to follow.

BUT! There is a BUT! Using a Compose action does not really do the job of making the flow easier to follow I believe. I created a new Power Automate idea to improve this part. You find it HERE and please vote for it if you agree with me that we should be able to set a name for a Compose action in order to get something better than “Output” when using it later on in the flow. Take a look later in this blog post, when I describe the second HTTP request, you will see that the Access Token is displayed as “Output”. Anyway – I have used a variable for Customer Type.

Using a variable for a field on the record which triggered the flow

Then we add a new action, this time a condition, in order to check if the field we used as filtering attribute has a certain value. In my case it is an option set and I only want to make the HTTP request if the filtering attribute has one of two values.

Now here I have learned something from my friend Jonas Rapp and that is to avoid nested conditions and to use guard conditions instead. This means that instead of continuing to build your flow logic in the no or yes part of the condition, you add a step “terminate” in yes or no (depending on which alternative should NOT continue) and you give this action a good name. The flow then becomes much easier to read and maintain. When it is collapsed you will see all the actions, which you would not have done otherwise. Take a look at what Jonas has to say about it in his blog post.

If Customer Type is equal to any of the two specified specified the flow should continue, if not – terminate the flow

Next I create two variables, one for each of the fields I want to get from the CDS/the Account record. As already mentioned, mostly because I think the flow gets easier to read and to make it easier to follow when looking at a run flow.

Two more variables, also from the Account record which triggered the flow. These we will use in the HTTP request.

Next I have added one more condition and that is because I want to make sure that we actually have values here when we do the HTTP request.

Making sure we have the values needed for our HTTP request

Now we are ready to add a HTTP request action. Remember I said the authentication model used here is OAuth 2.0. Probably there are different ways to accomplish such a request with a flow, but now I will let you in on how I did it. First we will make a HTTP request in order to recieve an access token and then we will use that token for the “real” HTTP request.

Since I had noticed that the HTTP action has a field called Authentication, under show advanced options, with an option for Active Directory OAuth 2.0 I first tried to go with that approach. So I created a HTTP request action, filled in the information I had received about the API and I tried to use the Authentication field and set it to Active Directory OAuth 2.0. First it complained about the grant_type “The request body must contain the following parameter: ‘grant_type” no matter what I did it felt like.

Google helpt me and I found this blog post. After reading it through I went with another approach and just skipped using the Authentication field, i.e. I let it say None in that field. The first http request, which gets me a token then looked like below.

HTTP request to get an access token

After some more investigation I actually got it to work also using the Authentication field. But only if I typed in the client id, resourse and secret in the body just as in the above picture, even though you get to type it in fields as well if you choose to use the Authentication field. I do not really see the difference in the two approaches, i.e. using the Authentication field or not.

In order to get hold on the Access Token from the HTTP request I used the same approach as how they did it in the blog post I mentioned. We want the output of the previous HTTP action. We use a Compose action and type in:  “@outputs(‘HTTP_2’).body.access_token”,  where ‘HTTP_2’ is the name of the previous HTTP Action with spaces replaced by underscores.

Hoovering over the Input of the Compose action

I tested the flow and voila, it got me an access token. Yay! First part accomplished. So then to the “real” HTTP request. I use the access token and I was supposed to send JSON in the body of the request, containing the Organisation number as well as the GUID for the Account record. The syntax should then be like this:

{

“Organisation_Number”:”123456-1234”

“Account”: “123e4567-e89b-12d3-a456-426655440000”

}

The HTTP request then looks like this:

Using the access token – “Outputs” in our next HTTP request

I then tested my flow, it made the API call and I received status 200, which means all is good and the rest of the story (what was expected to happen after my request) was all good as well.

As already mentioned, what is out of scope for this blog post is to make something of the received status and user friendly message from the API call. For instance you could add new fields to the Account record and write back the status, related message and date and place this information under an “Integration status” or “Admin” section on the form. Of course, it all depends on the overall picture and the specific situation/requirements in your case. But if you want some kind of notification in your Model-Driven Power App, that you have made the API call and you got a response back, it might be a good idea to write this info back to the CDS.


No comments:

Post a Comment