Standard Logic App and authentication with EasyAuth
Posted on: November 18, 2024I’ve previously blogged about EasyAuth e.g., App Service and OpenID Connect with Salesforce and Application Gateway and App Service authentication.
In this post, I’ll show how to use authentication with EasyAuth in a Standard Logic App. This post heavily builds on top of the post: Trigger workflows in Standard logic apps with Easy Auth.
Scenario:
- Logic App is secured with Entra ID authentication
- Logic App has an HTTP trigger
- Only 2 specific client applications are allowed to call the Logic App
- PowerShell to create necessary Entra ID app registrations
- Infrastructure as code in Bicep
We’ll create 3 app registrations, so that we can test authentication with Logic App:
First, we’ll create the app registration used by the Logic App authentication:
# Workflow application:
$integrationApp = New-AzADApplication `
-DisplayName "Integration Workflow" `
-SignInAudience AzureADMyOrg
Update-AzADApplication -InputObject $integrationApp `
-IdentifierUri "api://$($integrationApp.AppId)"
New-AzADServicePrincipal -ApplicationId $integrationApp.AppId
Similarly, we’ll create 3 client applications and their secrets:
# Integration client application 1:
$integrationClientApp1 = New-AzADApplication `
-DisplayName "Integration Client 1" `
-SignInAudience AzureADMyOrg
New-AzADServicePrincipal -ApplicationId $integrationClientApp1.AppId
$integrationClientApp1Secret = New-AzADAppCredential `
-ObjectId $integrationClientApp1.Id `
-EndDate (Get-Date).AddYears(1)
Repeat the above for the other client applications:
Next, we’ll prepare for the infrastructure-as-Code deployment. We have to pass clientId and integrationClientIds as parameters, so that the Logic App can be configured with the correct authentication settings. IntegrationClientIds is an array of client application IDs that are allowed to call the Logic App. No other client applications are allowed to call the Logic App. Here’s the deployment:
# Prepare parameters for the deployment:
$clientId = $integrationApp.AppId
$integrationClientIds = $integrationClientApp1.AppId, $integrationClientApp2.AppId
# Deploy the Standard Logic App with authentication enabled:
$deployment = .\deploy.ps1 -ClientId $clientId -IntegrationClientIds $integrationClientIds
$deployment.outputs.uri.value
Few key points from the deployment script:
- logicAppsAccessControlConfiguration is used to disable SAS authentication in triggers
- authsettingsV2 is used to configure EasyAuth settings including
allowedApplications
- WEBSITE_AUTH_AAD_ALLOWED_TENANTS app setting is used to restrict the tenant to the current tenant
- WEBSITE_AUTH_AAD_REQUIRE_CLIENT_SERVICE_PRINCIPAL app setting requires that incoming token to have object id (
oid
) claim
After the deployment, we can see the following resources in the resource group:
Now, we can implement simple HTTP trigger-based workflow using Azure Portal and leverage ready-made templates:
I’ll add simple payload to the response:
Now, we are ready to test our Logic App. I’ll first test with the Integration Client 1
application. Let’s get the token for the application:
# Integration Client 1 test:
$tenantId = (Get-AzContext).Tenant.Id
$clientPassword = ConvertTo-SecureString $integrationClientApp1Secret.SecretText -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential($integrationClientApp1.AppId, $clientPassword)
Connect-AzAccount -ServicePrincipal -Credential $credentials -TenantId $tenantId
$integrationClient1Token = Get-AzAccessToken -Resource $integrationApp.AppId -AsSecureString
$integrationClient1Token.Token | ConvertFrom-SecureString -AsPlainText | Set-Clipboard
Let’s quickly study the token in jwt.ms:
We can see that:
- The intended audience (
aud
) of the token matches theIntegration Workflow
- Application ID (
appid
) matches theIntegration Client 1
Now, we can test invoking the Logic App with the token:
Invoke-RestMethod `
-Uri $requestUri `
-Authentication Bearer `
-Token $integrationClient1Token.Token
The response is:
Hello Client App!
We can repeat the same steps for the Integration Client 2
application and see the same response.
Everything works as expected.
Let’s test with the Integration Client 3 - Not enabled
application.
Token seems to be similar as before and AppId matches our configured app:
However, when we try to call the Logic App with the Integration Client 3 - Not enabled
application, we get:
Invoke-RestMethod: You do not have permission to view this directory or page.
This is of course expected, since this application is not in the allowed client application list.
Let’s quickly see the configured setting of our Logic App:
Here’s a difference when comparing to typical App Service EasyAuth configurations:
So, we still need to allow unauthenticated access, since it is used by other operations e.g., by the Logic App designer.
More information about configuration options can be found from the official documentation:
Configure your App Service or Azure Functions app to use Microsoft Entra sign-in
Enable OAuth 2.0 with Microsoft Entra ID
What is the difference between allowedApplications
and identities
in the configuration?
- You can use
identities
to limit the access to specific directory object ids (oid
) - You can use
allowedApplications
to limit the access to specific client ids (appid
orazp
) - When you have an application that accesses the API as the signed-in user (delegated permissions), then the object id (
oid
) is the user’s object id
I’ll leave the delegated permissions scenario for another blog post.
You can further down narrow the access by defining more granular application roles: Daemon client application (service-to-service calls) Here is my App Service authentication and service-to-service integration example about it.
Conclusion
The above steps showed how to secure a Standard Logic App with EasyAuth authentication. Please remember, that this was only about the identity part. There are other aspects to consider when securing your Logic App including network restrictions etc.
This scenario was about the incoming requests to Logic App. If you need to call other services from the Logic App, you need to consider the outgoing requests as well. Typically, you would use Managed Identity for that.
You can find the full source code from my GitHub repository. Just open setup.ps1
and run commands line by line
and you have the same setup as I had in this blog post:
I hope you find this useful!