In the recent past at an organisation that shall not be named I came across an implementation that had some “security limitations”.
A Function App had been built that had two main functions: get a client token when a user was adding credit card details through the Braintree drop in, and secondly, process all sorts of server side Braintree operations including actually submitting payments, processing refunds, and much more.
This particular implementation had a fatal flaw: the client was provided (in the background, through javascript) the subscription key that gave access to the whole Function App.
A badly meaning user could copy that super secret key very easily by inspecting the network traffic (Ctrl + Shift + I) and then take it home. They could then process any transaction they wanted, including payments and refunds – and this would be totally outside the Power Apps environment the Function App was designed to be called from. If they were a bad actor, they could have retained this long after they left the organisation and caused all sorts of havoc.
As soon as I discovered the flaw (which did not reach production) I quickly discussed it with the relevant people and properly segmented the functionality.
The above example, to be fair, isn’t specific to D365 – it was just a poor implementation with a developer who likely didn’t appreciate the difference between client side and server side correctly, and didn’t seriously consider security as part of their implementation.
What it does relate to is the general fact that a lot of developers don’t understand how authentication is handled in D365, and therefore often use dodgy workarounds.
One common trick or workaround I have seen, and the subject of this article, is the creation of a Power Automate cloud flow with an HTTP trigger. The flow is callable by anyone with the URL (which to be fair, does have a secret key included). Developers create this flow then attempt to write some form javascript that triggers this cloud flow, and they simply either hardcode the flow URL or fetch it from environment variables. From their perspective, they’ve found an easy way to trigger grunty server side actions easily from within a small piece of code.
Do you see what the issue is though?
Spoiler alert: it’s almost the same as the above example. With this implementation the client gains access to the secret appended to the flow URL and can then retain this and use it outside the environment.
But it doesn’t have to be this way.
If you are writing form javascript in D365, you can take actions on behalf of the user who is already authenticated. Most people think of this solely in terms of retrieving records with the web API. However, if you think of this more broadly you can call third party services a lot more securely.
How?
By using a custom action added to your plugin assembly
Just like you can retrieve records, you can call a custom action through the web API. The platform then handles all of the authentication. Once the call reaches your custom action, you can be assured it has come from a legitimate user who currently has permission to access your environment (and you can also use security roles to manage who can call this).
So you’ve called your custom action – now what?
Whatever you want. If, for example, you want to call an external API or something like a Function App, the custom action, running on the server, will be the only part of the puzzle that actually gets access to the secret for the Function App (for example, you would store a client ID and secret in the plugin assembly’s secure configuration. Using that client ID and secret you would call the key vault to access any further secrets, then you would execute the action). The custom action would then return the ultimate result to the user.
During this whole process, no extra authentication has needed to happen, and no secrets have been silently exposed to the user. By keeping it simple, you’ve secured your implementation by 10x.
It has shocked me in interviews the number of developers that have been working in this area for 5-10 years plus and are not sure (or are not able to articulate) which processes run on the client side versus the server side, so I do recommend asking questions around this when recruiting. Getting this wrong does create real vulnerabilities.

Leave a comment