I’m using managed identity to let a Dataverse plug-in call Azure resources without storing secrets. One of those calls hits a Logic App (Consumption) via the When an HTTP request is received trigger. I wanted to ensure the workflow can only be invoked by callers from my tenant using OAuth—no shared access signature (SAS) keys. (If you’re on Logic Apps Standard, you’d typically use App Service “Easy Auth”.)
Microsoft’s docs say you can require OAuth and (critically) you must disable SAS for request triggers in Consumption, otherwise a valid SAS bypasses OAuth. The official instructions work, but I found a simpler way to flip the SAS switch directly in code view.
"parameters"
(top level) and Save:"accessControl": {
"triggers": {
"sasAuthenticationPolicy": {
"state": "Disabled"
}
}
}
This disables SAS so OAuth can’t be bypassed. (This is equivalent to what the docs recommend; adding it here is the fastest way.)
⚠️ Important:
accessControl
snippet will not appear again the next time you open code view. The setting still applies, it’s just hidden.Tip: If you automate deployments, include this in your ARM/Bicep/Template spec rather than patching after the fact.
In the Logic App, go to Authorization.
Click + Add policy ➜ OAuth 2.0.
Enter:
https://sts.windows.net/<tenant-guid>/
(v1) orhttps://login.microsoftonline.com/<tenant-id>/v2.0
(v2)https://management.azure.com
.Save.
The OAuth policy validates the token’s iss
and aud
claims on inbound calls to the request trigger.
If you want to ensure that only a specific managed identity can access this logic app you can additional add a custom claim onto the OAuth profile. To do this add a custom claim in the OAuth Profile. Set the claim name as appid
and set the value to the id of your managed identity. This will ensure that only that managed identity can call this Logic App. You can add multiple OAuth profiles to allow for more managed identities if you want.
On first run I got issuer or audience mismatch errors. My Dataverse plug-in was acquiring a token whose issuer looked like:
https://sts.windows.net/<tenant-guid>/
(AAD v1 style)…but I had configured the Logic App policy with:
https://login.microsoftonline.com/<tenant-id>/
(different issuer format)To debug, I had my plug-in log the raw access token, then pasted it into https://jwt.ms to inspect the claims. I updated the Logic App policy to use the exact issuer from the token, and everything worked.
Quick refresher:
- Issuer (
iss
) must match exactly, including trailing slash and version (v1 vs v2.0).- Audience (
aud
) must match the resource you requested when you got the token (e.g.,https://management.azure.com
for ARM).
When you call your Logic App from the plug-in, capture and trace the bearer token you’re sending. For example:
// inside Execute(IServiceProvider serviceProvider)
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var tracing = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
// Acquire the token with managed identity
string accessToken = context.ManagedIdentityService.AcquireToken("https://management.azure.com");
// Output the full token (needed for jwt.ms inspection)
tracing.Trace("AccessToken: {0}", accessToken);
// …then send HTTP request with Authorization: Bearer {accessToken}
⚠️ Note: Output the entire token (not truncated) if you want to paste it into jwt.ms for inspection of iss
and aud
. Also make sure to remove this tracing before deployment.
Original Post http://www.richardawilson.com/2025/08/locking-down-logic-app-consumption-with.html