# Microsoft Defender for Identity

You can connect Incode identity verification to Microsoft Sentinel so that when Defender for Identity raises a suspicious activity incident, your security team can send the flagged user a biometric verification link. The result is posted back to Sentinel automatically, giving your team the identity confirmation they need to resolve or escalate the incident.

This integration works well for Identity Threat Detection and Response (ITDR) workflows where you need to distinguish real security incidents from false positives. False positives can be caused by legitimate employees travelling, working from new devices, or logging in at unusual hours.

***

## Prerequisites

Ensure you have the following before you begin:

- An active Azure subscription with permissions to create Logic Apps and assign roles within a resource group
- A Microsoft Sentinel workspace
- Access to the Integrations page in Dashboard. Contact your Incode Representative if you do not see it.
- Users as directory records in the Incode integration. This is needed for verification requests to succeed.

***

## Integration Flow

The integration runs on two Azure Logic Apps deployed in your Azure environment:

1. The first is a **Sentinel automation playbook**. When Sentinel creates an incident, the playbook calls the Incode API to generate a unique verification link for the flagged user and delivers it to your security team. Your security team then sends it to the user.
2. The second is a **webhook receiver**. When the user completes their biometric check, Incode sends the result to this receiver. The receiver reads the result and updates the Sentinel incident, closing it as a false positive if verification succeeded, or escalating it to high severity if verification failed.

Both Logic Apps use a managed identity to authenticate against:

- Azure Key Vault for Incode credentials.
- Microsoft Sentinel to update incidents.

No credentials are hardcoded.

***

## Set Up the Sentinel Integration

### Create an Integration in Dashboard

1. Log in to Dashboard.
2. In the left menu, click **Integrations**.
3. Click **New Integration**.
4. From the Custom tab, click **API**, then click **Continue**.
5. Enter a **Name** for the integration: for example, `Microsoft Defender`.
6. Click **Save**.
7. Open the integration card and note the **Integration ID**. You'll need this in a later step.

### Collect Your Incode Credentials

Store the following values in Azure Key Vault. See [Find Integration Details](https://developer.incode.com/docs/manage-integrations) for where to locate each one in Dashboard.

- **Client ID**: Your OAuth client identifier.
- **Client secret**: Generate a new one if you don't already have one.
- **API key**: Obtain from your Incode account team if you don't have one.
- **Integration ID**: The value from the previous set of steps.
- **Auth server URL**: `https://auth.demo.incode.com` (demo) or `https://auth.incode.com` (production).
- **API base URL**: `https://demo-api.incodesmile.com` (demo) or `https://saas-api.incodesmile.com` (production).

### Deploy the Azure Resources

Incode provides both Logic Apps as ready-to-deploy ARM templates. Click **Deploy to Azure** in the [Incode GitHub repository](https://github.com/incode) to deploy both Logic Apps and an Azure Key Vault into your Azure subscription.

> 📘 Note
>
> If you don't have access to the ARM templates yet, contact your Incode account team.

After deploying, store the following secrets in Key Vault using the exact secret names shown:

| Secret name                    | Value                                           |
| ------------------------------ | ----------------------------------------------- |
| `incode-client-id`             | Your Incode OAuth client ID                     |
| `incode-client-secret`         | Your Incode OAuth client secret                 |
| `incode-api-key`               | Your Incode API key                             |
| `incode-integration-reference` | Your integration ID from the first set of steps |
| `incode-auth-url`              | Auth server URL from the previous set of steps  |
| `incode-api-base-url`          | API base URL from the previous set of steps     |

> 📘 Note
>
> To store secrets with special characters, use the Azure Cloud Shell Python approach to avoid bash misreading them:
>
> ```python
> python3 -c "
>
> import subprocess
>
> [subprocess.run](http://subprocess.run)(['az', 'keyvault', 'secret', 'set',
>
> '--vault-name', 'YOUR_KEYVAULT_NAME',
>
> '--name', 'incode-client-secret',
>
> '--value', 'YOUR_SECRET_VALUE_HERE'])
>
> "
>
> `
> ```

After storing all secrets, grant the Logic App managed identity **Get** and **List** permissions on Key Vault secrets.

### Assign the Sentinel Responder Role

Grant the managed identity the **Microsoft Sentinel Responder** role from Azure Cloud Shell:

```bash
az role assignment create \
  --assignee YOUR_MANAGED_IDENTITY_PRINCIPAL_ID \
  --role "Microsoft Sentinel Responder" \
  --scope /subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RESOURCE_GROUP
```

> 📘 Note
>
> Role assignments can take up to 10 minutes to propagate. Wait before testing.

### Configure Webhooks in Dashboard

The webhook receiver Logic App needs to receive session results from Incode when a user completes verification.

1. In Dashboard, click **Configuration** in the left menu.
2. Click the **Webhooks** tab.
3. Find the Flow or Workflow associated with your integration.
4. Add the webhook receiver Logic App URL as the endpoint for the `SESSION_SUCCEEDED` and `SESSION_FAILED` events.

To find the receiver Logic App URL, open the Logic App in the Azure portal, go to **Overview**, and copy the **Workflow URL**.

> 📘 Note
>
> Incode requires a webhook authentication secret to be configured before session webhooks are delivered. Contact your Incode Representative to confirm the required format for your environment.

### Connect Sentinel to the Playbook

1. In Microsoft Sentinel, create a new automation rule.
2. Set the trigger to **When an Incident is Created**.
3. Configure conditions to match the incidents you want to trigger verification for: for example, by severity or incident type.
4. Set the action to **Run Playbook** and select the playbook Logic App.
5. Click **Save**.

***

## Test the Integration

Test the end-to-end flow from Azure Cloud Shell:

```bash
curl -s -X POST \
  "YOUR_PLAYBOOK_TRIGGER_URL" \
  -H "Content-Type: application/json" \
  -d '{"incidentId":"TEST-001","severity":"Medium","userEmail":"user@yourdomain.com"}' \
  | python3 -m json.tool
```

A successful response includes a `verificationUrl` field and a `status` of `verification_initiated`. Open the URL to complete a test biometric check, then confirm the Sentinel incident was updated as expected.

***

## Technical Notes

- **The&#x20;**`api-version: 1.0`**&#x20;header is required.** Every call to the Incode B2B onboarding endpoint (`POST /omni/b2b/onboarding/request-new`) must include the header `api-version: 1.0`. Without it, the API returns HTTP 406 with no explanation.
- `externalCustomerId`**&#x20;is required for incident correlation.** Pass the Sentinel incident ID as `externalCustomerId` in every B2B onboarding request. Incode echoes this value back in the session webhook payload. Without it, the webhook receiver cannot identify which incident to update.
- **Users must exist in the Incode directory before verification.** If the `loginHint` (user email) does not match any record in the integration directory, the API returns error `5504: Employee by login factor cannot be found`. Add the user to the integration directory in Dashboard before retrying.

***

## Troubleshooting

### **Playbook Fails at OAuth Token Step with HTTP 401**

The client ID or client secret in Key Vault is wrong or has been rotated. Confirm credentials manually from Cloud Shell:

```bash
curl -s -X POST "{auth_url}/oauth2/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&scope=openid&client_id={client_id}&client_secret={client_secret}"
```

### **Playbook Fails at B2B Onboarding Step with HTTP 406**

The `api-version: 1.0` header is missing from the HTTP action in the Logic App.

### **Playbook Fails with Error 5504**

The user email passed as `loginHint` does not exist in the Incode integration directory. Add the user in Dashboard and retry.

### **Webhook Receiver Never Fires After Verification Completes**

There are three possible causes:

- Session webhooks are not configured in Dashboard for the correct Flow or Workflow.
- The webhook auth secret is missing or incorrectly configured.
- The webhook is configured at the wrong level (session webhooks are scoped to individual Flows or Workflows, not globally).

### **Webhook Receiver Fires but Sentinel Update Fails with HTTP 403**

The managed identity does not have the Microsoft Sentinel Responder role, or the role assignment has not yet propagated. Wait up to 10 minutes and retry.

### **Sentinel Incident is Not Updated After Verification Completes**

The `externalCustomerId` in the webhook payload does not match a valid Sentinel incident ID. Confirm that the incident ID is being correctly passed in the original B2B onboarding request.

***

## Supported Environments

| Environment | Auth server URL                | API base URL                       |
| ----------- | ------------------------------ | ---------------------------------- |
| Demo        | `https://auth.demo.incode.com` | `https://demo-api.incodesmile.com` |
| Production  | `https://auth.incode.com`      | `https://saas-api.incodesmile.com` |

<br />
