ILAP Analytics authenticates users and services with Microsoft Entra ID, which requires two app registrations — one for the analytics API and one for the analytics UI. This page shows how to create and configure both with the Azure CLI (az), including the app roles, exposed API scopes, Microsoft Graph permissions, redirect URIs, and admin consent. It is written for the IT administrator (or identity administrator) preparing an ILAP Analytics environment. Repeat the process once per environment (Dev, Beta, Test, Prod).
Run the script, or run the commands step by step
The commands below are also packaged as ready-to-run scripts in the deployment package under Azure.IaC/Scripts/:
- Bash (Linux/macOS):
setup-app-registrations.azcli - PowerShell (Windows):
setup-app-registrations.ps1
Edit the CONFIG block at the top of the script (app names, UI URL, tenant), run it, and it performs every step on this page and prints the values for your Bicep parameter file. The commands shown here are in Bash syntax; on Windows either use the PowerShell script or adjust the variable syntax ($env: / $var). The steps that patch nested properties (exposed scopes, app roles, redirect URIs) send a small JSON body to Microsoft Graph — the scripts build that JSON for you.
Prerequisites
You need the Application Developer role in Entra ID to create app registrations. If your organisation uses Privileged Identity Management, activate the role first (My roles → Application Developer → Activate). The final admin-consent step of each app additionally requires Global Administrator or Privileged Role Administrator — if you do not hold that role, ask someone who does to run those two commands.
Sign in to the target tenant:
az login --tenant '<your-tenant-id>'
# Well-known IDs used below
GRAPH_APP_ID='00000003-0000-0000-c000-000000000000' # Microsoft Graph
GRAPH_EMAIL='64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0'
GRAPH_OFFLINE='7427e0e9-2fba-42fe-b0c0-848c9e6a8182'
GRAPH_OPENID='37f7f235-527c-4136-accd-4a02d197296e'
GRAPH_PROFILE='14dad69e-099b-42c9-810b-d002981feec1'
Set up the API app registration
Step 1: Create the API app registration
Create the registration for the current organisation only, and capture its application (client) ID and object ID into variables for the following steps.
API_APP_ID=$(az ad app create \
--display-name 'ILAP Analytics API DEV' \
--sign-in-audience AzureADMyOrg \
--query appId -o tsv)
sleep 15 # allow Entra to replicate the new object
API_OBJ_ID=$(az ad app show --id "$API_APP_ID" --query id -o tsv)
Step 2: Set the Application ID URI
Expose the API under api://<api-app-id> so the UI can request its scopes.
az ad app update --id "$API_APP_ID" --identifier-uris "api://$API_APP_ID"
Step 3: Add the exposed scopes
Add two delegated scopes, user_impersonation and read. Both use type: User, which corresponds to Admins and users on the "who can consent" option. Generate a stable GUID for each scope and keep them — the UI app is granted these scopes later.
USER_IMP_SCOPE_ID=$(uuidgen)
READ_SCOPE_ID=$(uuidgen)
az rest --method PATCH \
--uri "https://graph.microsoft.com/v1.0/applications/$API_OBJ_ID" \
--headers "Content-Type=application/json" \
--body "{
\"api\": { \"oauth2PermissionScopes\": [
{ \"id\": \"$USER_IMP_SCOPE_ID\", \"value\": \"user_impersonation\", \"type\": \"User\", \"isEnabled\": true,
\"adminConsentDisplayName\": \"Access ILAP Analytics as the signed-in user\",
\"adminConsentDescription\": \"Allow the application to access ILAP Analytics on behalf of the signed-in user.\" },
{ \"id\": \"$READ_SCOPE_ID\", \"value\": \"read\", \"type\": \"User\", \"isEnabled\": true,
\"adminConsentDisplayName\": \"Read ILAP Analytics data\",
\"adminConsentDescription\": \"Allow the application to read ILAP Analytics data on behalf of the signed-in user.\" }
] }
}"
The two scopes you defined (user_impersonation and read) are needed later when configuring the UI application, and appear as api://<api-app-id>/user_impersonation and api://<api-app-id>/read.
Step 4: Add the application roles
Add the three app roles below. Use exactly these values (case sensitive). Readers and Writers allow both User and Application members so that applications using app-only tokens (for example managed-identity integrations) can be granted these roles; Admins is users only.
| Display name | Value | Allowed member types | Description |
|---|---|---|---|
| Admins | Administrator | Users/Groups | Can read/write data and add Metadata and Metadata Fields/Values |
| Writers | DataWriter | Both (Users/Groups + Applications) | Can write data to ILAP Analytics but cannot modify Metadata and Metadata Fields/Values |
| Readers | DataReader | Both (Users/Groups + Applications) | Can read data from ILAP Analytics. Writing is not permitted |
ADMIN_ROLE_ID=$(uuidgen); WRITER_ROLE_ID=$(uuidgen); READER_ROLE_ID=$(uuidgen)
az rest --method PATCH \
--uri "https://graph.microsoft.com/v1.0/applications/$API_OBJ_ID" \
--headers "Content-Type=application/json" \
--body "{
\"appRoles\": [
{ \"id\": \"$ADMIN_ROLE_ID\", \"displayName\": \"Admins\", \"value\": \"Administrator\", \"isEnabled\": true,
\"allowedMemberTypes\": [\"User\"],
\"description\": \"Can read/write data and add Metadata and Metadata Fields/Values\" },
{ \"id\": \"$WRITER_ROLE_ID\", \"displayName\": \"Writers\", \"value\": \"DataWriter\", \"isEnabled\": true,
\"allowedMemberTypes\": [\"User\", \"Application\"],
\"description\": \"Can write data to ILAP Analytics but cannot modify Metadata and Metadata Fields/Values\" },
{ \"id\": \"$READER_ROLE_ID\", \"displayName\": \"Readers\", \"value\": \"DataReader\", \"isEnabled\": true,
\"allowedMemberTypes\": [\"User\", \"Application\"],
\"description\": \"Can read data from ILAP Analytics. Writing is not permitted\" }
]
}"
Step 5: Add Microsoft Graph permissions and consent
Add the delegated Graph permissions email, offline_access, openid, and profile, create the service principal (enterprise application), then grant admin consent.
az ad app permission add --id "$API_APP_ID" --api "$GRAPH_APP_ID" \
--api-permissions "$GRAPH_EMAIL=Scope" "$GRAPH_OFFLINE=Scope" "$GRAPH_OPENID=Scope" "$GRAPH_PROFILE=Scope"
az ad sp create --id "$API_APP_ID"
az ad app permission admin-consent --id "$API_APP_ID" # needs Global Admin / Privileged Role Admin
Set up the UI app registration
Step 1: Create the UI app registration
UI_APP_ID=$(az ad app create \
--display-name 'ILAP Analytics UI DEV' \
--sign-in-audience AzureADMyOrg \
--query appId -o tsv)
sleep 15
UI_OBJ_ID=$(az ad app show --id "$UI_APP_ID" --query id -o tsv)
Step 2: Configure the redirect URIs
Add the single-page-application (SPA) redirect URI (the URL of your web UI app) and a public-client / desktop redirect URI (http://localhost/oauth2/callback, used by the IlapAdapter desktop client), and enable the public-client flow. If you use a custom domain for the API, use your UI custom-domain URL as the SPA redirect.
UI_REDIRECT_URI='https://app-ilapanalytics-ui-dev.azurewebsites.net'
DESKTOP_REDIRECT_URI='http://localhost/oauth2/callback'
az rest --method PATCH \
--uri "https://graph.microsoft.com/v1.0/applications/$UI_OBJ_ID" \
--headers "Content-Type=application/json" \
--body "{
\"spa\": { \"redirectUris\": [\"$UI_REDIRECT_URI\"] },
\"publicClient\": { \"redirectUris\": [\"$DESKTOP_REDIRECT_URI\"] },
\"isFallbackPublicClient\": true
}"
Step 3: Add Microsoft Graph permissions
The UI needs the user's profile to sign them in — add the same delegated Graph permissions.
az ad app permission add --id "$UI_APP_ID" --api "$GRAPH_APP_ID" \
--api-permissions "$GRAPH_EMAIL=Scope" "$GRAPH_OFFLINE=Scope" "$GRAPH_OPENID=Scope" "$GRAPH_PROFILE=Scope"
Step 4: Grant access to the API, and consent
Grant the UI delegated access to both API scopes (user_impersonation and read) so it can call the API on behalf of the signed-in user, create the service principal, then grant admin consent.
az ad app permission add --id "$UI_APP_ID" --api "$API_APP_ID" \
--api-permissions "$USER_IMP_SCOPE_ID=Scope" "$READ_SCOPE_ID=Scope"
az ad sp create --id "$UI_APP_ID"
az ad app permission admin-consent --id "$UI_APP_ID" # needs Global Admin / Privileged Role Admin
Step 5: Application owners
Register at least one application owner on each registration. Some organisations require at least two permanent employees as owners — follow your corporate policy.
OWNER_OBJECT_ID=$(az ad user show --id 'owner@yourcompany.com' --query id -o tsv)
az ad app owner add --id "$API_APP_ID" --owner-object-id "$OWNER_OBJECT_ID"
az ad app owner add --id "$UI_APP_ID" --owner-object-id "$OWNER_OBJECT_ID"
Assign users to the application roles
Users and groups are granted access on the API enterprise application by assigning them one of the app roles (Administrator, DataWriter, DataReader). Assign a user with the Azure CLI as follows (repeat per user/group, choosing the role ID from Step 4):
USER_OBJECT_ID=$(az ad user show --id 'user@yourcompany.com' --query id -o tsv)
API_SP_ID=$(az ad sp show --id "$API_APP_ID" --query id -o tsv)
az rest --method POST \
--uri "https://graph.microsoft.com/v1.0/servicePrincipals/$API_SP_ID/appRoleAssignedTo" \
--headers "Content-Type=application/json" \
--body "{ \"principalId\": \"$USER_OBJECT_ID\", \"resourceId\": \"$API_SP_ID\", \"appRoleId\": \"$ADMIN_ROLE_ID\" }"
See User Permissions for what each role can do.
Record your app registration details
Once both app registrations exist, record the following for each environment you set up (Dev, Beta, Test, Prod). These values are needed when you configure the Bicep parameters and the IlapAdapter client software. The setup script prints them all at the end.
| Name | Environment | Usage | ClientId / Scope |
|---|---|---|---|
| ILAP Analytics api <env> | e.g. DEV | Api | api://<api-app-client-id>/user_impersonation |
| ILAP Analytics ui <env> | e.g. DEV | Web UI and authentication for Winforms | <ui-app-client-id> |
Authentication settings
These settings are required for connecting to the different environments from the IlapAdapter client software. Record them per environment:
| Property | Value |
|---|---|
| Authority | https://login.microsoftonline.com/<your-tenant-id>/v2.0 |
| Scopes | api://<api-app-client-id>/user_impersonation User.Read offline_access |
| Api Url | Base URL of your analytics API app (use your custom domain if applicable), e.g. https://<api-app-name>.azurewebsites.net/api/ |
| ClientId | <ui-app-client-id> |
Was this article helpful?
That’s Great!
Thank you for your feedback
Sorry! We couldn't be helpful
Thank you for your feedback
Feedback sent
We appreciate your effort and will try to fix the article