Empirum REST API - Identity Provider Principals
Additional Configuration for On-Premises Installations
Table of Contents
Overview
Support for identity provider principals in the Empirum REST API does not work out of the box for on-premises customers. In addition to managing identity provider principals in the Admin UI, as described in Empirum REST API Technical Reference and Implementation, the configuration steps below are required.
If any of these steps is missing, an otherwise valid token is rejected with 403 Forbidden.
Required Configuration
| Step | What to do |
|---|---|
| 1. Azure app registration | Register an API application and a client application in Microsoft Entra ID. On the API application, configure Expose an API. |
| 2. identity-providers.json | Add a matching entry for the identity provider to identity-providers.json on the REST API side. |
| 3. Role assignment | Assign roles to the identity provider principal separately in the Permission Management web app. |
Roles are not assigned through Entra App Roles. Role assignments configured in Entra ID are not evaluated by the Empirum REST API.
Step 1: Azure app registration
Two Azure (Entra) app registrations are involved:
- One for the API itself: registered once, represents the Empirum REST API as a protected resource ("audience") in your tenant.
- One per client application: registered once per application or script that will call the API. Each client is either a Service Client (unattended, uses a client secret) or a Public Client (interactive, a human signs in).
Information to collect
| Value | Where to find it | Used for |
|---|---|---|
| Directory (tenant) ID | App registration → Overview |
identity-providers.json → authority
|
| API app registration's Application (client) ID | API app registration → Overview |
identity-providers.json → audience
|
| Client app registration's Application (client) ID | Each client app registration → Overview | Token request (client_id) |
| Client secret (Service Client only) | Client app registration → Certificates & secrets | Token request (client_secret) |
| Object ID of the calling identity | Service principal (Service Client) or user (Public Client) → Overview | Registered in Empirum as a Client/User principal |
Register the API
Do this once per Empirum instance.
- In the Azure Portal, go to Microsoft Entra ID → App registrations → New registration.
- Name it, e.g. Matrix42 Empirum REST API. Leave the redirect URI empty. Click Register.
- On the Overview page, copy:
-
Application (client) ID: this becomes the
audiencefor your instance. -
Directory (tenant) ID: this becomes part of the
authorityURL.
-
Application (client) ID: this becomes the
- Go to Expose an API → click Add next to "Application ID URI" → accept the default (
api://<Application-ID>) or set a custom URI → Save.
The Expose an API step is required. Without it, client token requests using scope=<api-client-id>/.default fail, because the API is not yet a valid audience in your tenant.
Register a client application
Repeat this once per application or script that should call the API. Pick the variant that matches how the application runs:
| Service Client | Public Client | |
|---|---|---|
| Flow | Client Credentials | Device Code / Authorization Code |
| Who authenticates | The application itself | A human user, interactively |
| Credentials | Client ID + Client Secret | None (browser sign-in / device code) |
| Typical use case | Scheduled scripts, services, CI/CD | Admin tools, interactive PowerShell sessions |
Service Client (unattended scripts and services)
- Go to App registrations → New registration → name it, e.g. Matrix42 Empirum PowerShell Client → Register.
- Copy its Application (client) ID.
- Go to Certificates & secrets → New client secret → copy the generated value immediately.
- On the Overview page, note the Object ID of the application's service principal (listed under "Managed application in local directory"). You register this value in Empirum in the role assignment step.
The client secret value is shown only once. Store it in a password manager or your application's secret store before leaving the page.
No API permission needs to be granted to this app registration in the Azure Portal. The client simply requests scope=<api-client-id>/.default, and Empirum resolves what it is allowed to do from its own role assignment, not from Entra.
Public Client (interactive sign-in)
- Go to App registrations → New registration → name it, e.g. Matrix42 Empirum Interactive Client → Register.
- Copy its Application (client) ID.
- Go to Authentication → Add a platform:
-
For Device Code: choose Mobile and desktop applications, select
http://localhostas redirect URI, and enable Allow public client flows. -
For Authorization Code: choose Web and set the redirect URI to
http://localhost.
-
For Device Code: choose Mobile and desktop applications, select
No client secret is needed. Each user who signs in authenticates with their own Entra account. Their Object ID (visible under their user profile in Entra, or captured automatically on first interactive sign-in) is what gets registered in Empirum.
Step 2: identity-providers.json
Make this change in the DBUtil installation directory, then (re-)install the REST API service through DBUtil. Do not edit the files directly in the running service's installation folder.
Installing or updating the REST API service through DBUtil replaces the entire service directory. Any change to appsettings.json or Data/identity-providers.json made directly in the installed service folder is lost the next time DBUtil (re-)installs the service. Always make the change in the DBUtil installation directory first, then let DBUtil (re-)install the service so the change is copied into place correctly.
- On the Empirum server, open the folder that DBUtil uses to install the REST API service (next to
Setup.inf, alongside the REST API'sappsettings.jsonandData\identity-providers.jsonfiles). - Copy
identity-providers.local.json.exampletoidentity-providers.local.jsonin the same folder and fill in the placeholders (see the example and field table below). - Optional: if you also want a Sign in with Entra ID button on the Permission Management login page (
/admin), copyappsettings.local.json.exampletoappsettings.local.jsonin the same folder and fill in the matching placeholders there as well. - Run the REST API service (re-)installation through DBUtil so the updated configuration is picked up.
- Confirm the identity provider is active: sign in to
/admin(if you enabled the Entra sign-in button in step 3), or request a token as shown in Obtaining a token and calling the API.
Example identity-providers.local.json:
{
"providers": [
{
"name": "contoso-entra",
"authority": "https://login.microsoftonline.com/<tenant-id>/v2.0",
"audience": "<api-app-registration-client-id>"
}
]
}| Field | Value |
|---|---|
authority |
https://login.microsoftonline.com/<Directory (tenant) ID>/v2.0, using the tenant ID from the app registration step |
audience |
Application (client) ID of the API app registration from the app registration step |
name |
Any label to recognize this provider later; not security-relevant |
Step 3: Role assignment
Entra only authenticates the caller; it does not grant any roles. Once the identity provider is configured, the identity from the app registration step can obtain a token, but every API call still returns 403 Forbidden until it is assigned roles on the Empirum side.
- Sign in to Permission Management (
/admin) with an account that already hasadmin.manage(e.g. the ADMIN Local Principal created during installation). - Under Local Principals (the same page also lists Entra-backed principals once they exist), find or add the identity:
- Service Client: use the PermissionManager tool, or wait for its first API call, which auto-creates a zero-role row. Assign roles to the Object ID of its service principal.
- Public Client / interactive user: either let the user sign in once (a zero-role row is created automatically on first token use), or use the EntraRegistration tool, which signs the user in interactively and registers their Object ID automatically.
- Assign only the roles the application actually needs (least privilege). See the role reference in Cloud Permission Management & Local Principals → Choosing roles.
Until roles are assigned, requests authenticate successfully (200 on the token request) but every API call fails with 403. This is expected and not a configuration error.
Obtaining a token and calling the API
In both flows, scope must be <api-app-id>/.default. This is the standard way to request the API's audience as a scope.
Service Client (Client Credentials Flow)
$body = @{
grant_type = 'client_credentials'
client_id = '<client-app-id>'
client_secret = '<client-secret>'
scope = '<api-app-id>/.default'
}
$response = Invoke-RestMethod -Method Post `
-Uri 'https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token' `
-Body $body
$token = $response.access_token
Invoke-RestMethod -Uri 'http://localhost:5057/api/computer' `
-Headers @{ Authorization = "Bearer $token"; 'api-version' = '1' }Public Client (Device Code Flow)
Interactive, no browser automation needed. Requires the MSAL.PS module (Install-Module MSAL.PS).
$token = Get-MsalToken `
-ClientId '<public-client-app-id>' `
-TenantId '<tenant-id>' `
-Scopes '<api-app-id>/.default' `
-DeviceCode
Invoke-RestMethod -Uri 'http://localhost:5057/api/computer' `
-Headers @{ Authorization = "Bearer $($token.AccessToken)"; 'api-version' = '1' }You are prompted with a code and the URL https://microsoft.com/devicelogin. Sign in there with the client's user account.