Skip to content

Repository files navigation

Claim Validation — Logic App Standard POC

A Logic App Standard proof-of-concept that validates Microsoft Entra Verified ID claims during account recovery.

Overview

This workflow is a low-code implementation of an Entra Verified ID claim-validation endpoint. It receives the Verified ID claim-validation callout from Entra, looks up the employee by UPN, compares the supplied documentNumber claim against the authoritative record, and returns a pass/fail decision — all using Logic App actions instead of compiled code.

┌─────────────┐     ┌────────────────────────┐     ┌─────────────────────┐
│   Entra     │────▶│  ClaimValidation        │────▶│  employees.json     │
│  Recovery   │     │  (Logic App Standard)   │     │  (Blob / HTTP URL)  │
│    Flow     │◀────│                         │◀────│                     │
└─────────────┘     └────────────────────────┘     └─────────────────────┘

How it works

  1. Trigger — An HTTP Request trigger (When_a_claim_validation_request_is_received) receives the Entra Verified ID claim-validation callout.
  2. Download dataDownload_Employee_Data performs an HTTP GET against the employee data URL (an anonymous-read blob or any HTTP-hosted employees.json).
  3. Extract — The UPN and documentNumber claim are extracted from the request body.
  4. Match — The workflow filters the employee list by UPN, then compares the supplied documentNumber against the matched record's DocumentId (case-insensitive).
  5. Respond — Returns a Graph-shaped pass/fail response:
    • pass — UPN found and document number matches.
    • fail (documentNumber) — document number mismatch.
    • fail (employeeNotFound) — no employee matched the UPN.
    • fail (documentNumberMissing) — the documentNumber claim was absent.

Response shape

{
  "data": {
    "@odata.type": "microsoft.graph.onVerifiedIdClaimValidationCalloutData",
    "verifiedIdClaimValidationResult": "pass"
  }
}

Prerequisites

Deploy

Deployment is four steps and the order matters:

flowchart LR
    A["Step 1 - Provision infra<br/>Storage + Plan + empty Logic App"] --> B["Step 2 - Upload employees.json<br/>to Blob / HTTP"]
    B --> C["Step 3 - Deploy workflow files<br/>zip to Logic App"]
    C --> D["Step 4 - Test<br/>get callback URL and POST"]
Loading

⚠️ Don't stop after Step 1. The Deploy to Azure button (and the ARM template) create the infrastructure only — an empty Logic App. If you skip Steps 2-3 the Workflows blade shows No Workflows Found. The deploy.ps1 script (Step 1, Option B) does Steps 1 and 3 for you — you still do Step 2 and Step 4.

Step 1 — Provision the infrastructure

Creates the Storage Account, the WS1 hosting plan, and the (empty) Logic App Standard site. Pick one option below.

Option A — Deploy to Azure (ARM)

Deploy to Azure

The ARM template provisions the infrastructure only (Storage + WS1 plan + Logic App Standard). After it completes, continue to Step 2 and Step 3 — the Logic App is empty until you deploy the workflow files.

Parameters

Parameter Description
Logic App name Globally unique name for the Logic App Standard site. This is the only name you provide — the other two are derived from it.
App Service Plan name Derived: <logic-app-name>-plan. Leave as default.
Storage account name Derived: the Logic App name lowercased, with non-alphanumeric characters removed and trimmed to 24 chars. Leave as default.
Storage account type Standard_LRS / Standard_GRS / Standard_RAGRS.
Logic App SKU Hosting plan SKU (Workflow Standard tier): WS1 (default) / WS2 / WS3. See the note below.
Location Azure region.
Employee data URL (optional) HTTP(S) URL to employees.json. Surfaced as the EMPLOYEE_DATA_URL app setting.

Why Logic App Standard? This tier was chosen over Consumption because it runs on the dedicated Azure Functions host (always-warm, no cold-start) for low-latency synchronous pass/fail responses, supports file-based workflows in source control, and offers single-tenant isolation and VNet readiness suited to an identity flow. The plan SKU is parameterized (logicAppSku) and defaults to WS1 — scale up to WS2/WS3 for more vCPU/memory without changing anything else.

You can also deploy the template directly:

az deployment group create `
  --resource-group <your-rg> `
  --template-file ARMTemplate/template.json `
  --parameters logicAppName=<unique-name> employeeDataUrl=<https-url-to-employees.json>

Option B — End-to-end script (Bicep)

deploy.ps1 is the recommended path. It recompiles the ARM template from infra/main.bicep (keeping the two in sync), provisions the infrastructure, and zip-deploys the workflow files in one step:

.\deploy.ps1

Edit the configuration block at the top of deploy.ps1 ($subscriptionId, $resourceGroup, $location) before running.

Bicep is the source of truth. ARMTemplate/template.json is generated from infra/main.bicep (via az bicep build) so the Deploy to Azure button and the script never drift. To regenerate manually:

az bicep build --file infra/main.bicep --outfile ARMTemplate/template.json

Step 2 — Upload the employee data

The workflow downloads its employee records over HTTP. Host SampleData/employees.json somewhere the Logic App can reach anonymously and set the URL (the EMPLOYEE_DATA_URL app setting, or update the Download_Employee_Data action URL in ClaimValidation/workflow.json).

# Example: upload to a blob container with anonymous read access
az storage blob upload `
  --account-name <storageaccount> `
  --container-name employeedata `
  --name employees.json `
  --file SampleData/employees.json `
  --auth-mode login

Step 3 — Deploy the workflow

If you used Option A (ARM, infra only), package and deploy the workflow files to the Logic App. (Option B / deploy.ps1 already did this.)

Compress-Archive -Path host.json, connections.json, ClaimValidation -DestinationPath workflow.zip -Force
az functionapp deployment source config-zip `
  --resource-group <your-rg> `
  --name <logic-app-name> `
  --src workflow.zip

Logic App Standard runs on the Azure Functions host, so the deployment command is az functionapp deployment source config-zip. This is a hosting detail of Logic App Standard — the POC itself contains no Azure Functions application code.

Step 4 — Test

After deployment, get the workflow callback (trigger) URL and POST the sample request:

$callbackUrl = az rest --method POST `
  --uri "https://management.azure.com/subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Web/sites/<logic-app-name>/hostruntime/runtime/webhooks/workflow/api/management/workflows/ClaimValidation/triggers/When_a_claim_validation_request_is_received/listCallbackUrl?api-version=2024-04-01" `
  --query 'value' --output tsv

Invoke-RestMethod -Method Post -Uri $callbackUrl `
  -ContentType 'application/json' `
  -InFile SampleData/sample-request.json

Expected response for the sample request (jdoe@contoso.com / AB123456):

{ "data": { "@odata.type": "microsoft.graph.onVerifiedIdClaimValidationCalloutData", "verifiedIdClaimValidationResult": "pass" } }

Folder contents

Path Purpose
ClaimValidation/workflow.json The stateful workflow definition (trigger + claim-matching logic).
host.json Logic App Standard host configuration (Workflows extension bundle).
connections.json Managed API connections (empty — this POC uses an HTTP download, no connectors).
local.settings.json Local runtime settings for the Azure Functions Core Tools / Logic Apps designer.
ARMTemplate/template.json ARM template that provisions the Storage Account, App Service Plan (WS1), and Logic App Standard site. Generated from infra/main.bicep — do not edit by hand.
ARMTemplate/createUiDefinition.json Portal UI definition for the Deploy to Azure button.
infra/main.bicep Source of truth for the infrastructure. deploy.ps1 recompiles ARMTemplate/template.json from this on every run.
deploy.ps1 End-to-end PowerShell deployment (infra + workflow zip-deploy).
data/employees.json Runtime data file referenced by the workflow's HTTP download step.
SampleData/employees.json Sample employee data to upload to Blob Storage (or any HTTP host).
SampleData/sample-request.json Sample request payload for testing the workflow trigger.

Customizing the matching logic

  • Add records: edit SampleData/employees.json and re-upload.
  • Match on additional claims: extend the Check_DocumentNumber_Provided / Compare_DocumentNumber branches in ClaimValidation/workflow.json to compare more claim keys against their columns.
  • Use a real data source: replace the Download_Employee_Data HTTP action with a connector (SQL, HTTP API, Excel Online, etc.) and add the corresponding entry to connections.json.

About

Logic App Standard POC that validates Microsoft Entra Verified ID claims during account recovery.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages