Skip to content

1. Entra app registration

Owner: IT Why first: Cloud Ops cannot finish their Helm step until they have the tenant_id and client_id from this app registration. Schedule this before Cloud Ops starts.

The Roots Windows agent authenticates to ChainDB with a Microsoft Entra ID JWT, verified server-side through ChainDB’s generic OIDC path. There is no Arbium-specific identity provider, no shared secret on the wire, and no separate enrollment dance — the JWT is the proof.

This page sets up everything Arbium needs in your tenant: three Entra objects and two security groups. Some values come back to IT for the agent config script; the tenant ID, agent client ID, and group Object IDs are forwarded to Cloud Ops.

Object Kind What it’s for
Arbium Agent App registration Managed-device agents authenticate to ChainDB with a token issued for this app. (First section below.)
Arbium Admin App registration Admins sign into the web console (OIDC). Skip if Cloud Ops isn’t enabling the Admin UI.
Arbium SCIM Non-gallery enterprise app Entra automatically provisions your users and groups into Arbium through this app. It must be a non-gallery app — App registrations can’t do SCIM provisioning (their Provisioning tab is greyed out with “not supported”).
Security group Decides Becomes the Helm value
Arbium Admins who can open the admin console scim.scimAdminGroupIds
Arbium Users who is allowed to run the agent and send captures — also the group you scope the app install to in Intune scim.scimUserGroupIds

Both groups get assigned to the Arbium SCIM app, so Entra syncs them — and their members — into ChainDB. A person must be provisioned through SCIM before Arbium accepts their captures or admin sign-in.

Do the Arbium Agent section first — two of the values Cloud Ops needs (tenant ID + agent client ID) come from it.

In the Entra admin center (entra.microsoft.com), under your customer tenant:

  1. Applications > App registrations > New registration.
  2. Name: Arbium Agent (or similar).
  3. Supported account types: Accounts in this organizational directory only (single tenant).
  4. Leave Redirect URI empty for now — the WAM redirect URI is added in the Windows-specific step below.

Click Register. You now have an Application (client) ID and a Directory (tenant) ID — both visible on the Overview page.

Under the new app registration:

  1. Expose an API > Set Application ID URI. Accept the default api://<client-id> and Save.

  2. You do not need to add a custom scope. Accepting the Application ID URI is enough — the agent requests the resource-default scope for the app’s own GUID, i.e. <client-id>/.default. It derives this from the configured Application ID URI internally (it strips the api:// scheme and appends /.default).

    The scope must be the GUID-based <client-id>/.default, not the api://<client-id>/.default URI form. The agent requests a token for its own app (a self-token), and Entra only honors a self-token when the resource is the GUID-based App Identifier — it rejects the api:// form with AADSTS90009. A bare resource with no /.default is rejected with AADSTS500011 (resource api:/). The agent handles both; you just set EntraApiScope to api://<client-id> in Step 2.

The agent and ChainDB’s verifier expect v2 tokens:

  1. Manifest.
  2. Set "requestedAccessTokenVersion": 2.
  3. Save.

v2 tokens use the https://login.microsoftonline.com/<tenant>/v2.0 issuer and a bare-GUID audience. Without this flip, tokens come out v1 with sts.windows.net issuer and api://... audience, which ChainDB’s verifier rejects.

The Windows agent acquires Entra tokens silently through WAM (Web Account Manager) against the device’s Primary Refresh Token. Two app-reg settings are required.

  1. Add the WAM redirect URI. Authentication > Add Redirect URI > Mobile and desktop applications. The card pre-suggests several “Custom redirect URIs” with checkboxes — tick the one that already reads:

    ms-appx-web://microsoft.aad.brokerplugin/<your-application-client-id>

    (Entra has already substituted your client ID for you.) Save.

    The URI must be added under the Mobile and desktop applications card. Adding it under Web instead is a silent no-op for WAM and produces the same IncorrectConfiguration error as omitting it entirely.

  2. Enable public client flows. Same Authentication blade → scroll to Advanced settings → set Allow public client flows to Yes. Save. Without this, MSAL silent acquire returns WAM IncorrectConfiguration even when the redirect URI is correct.

API permissions > Grant admin consent for <tenant>. You do not need to add any new permissions — Entra has already added User.Read from Microsoft Graph by default, which is fine. This consent covers the app registration’s own API permissions so the agent can mint tokens against it.

Without admin consent, MSAL silent acquire returns WAM IncorrectConfiguration (same error code as missing redirect URI or disabled public client flows). All three knobs — redirect URI, public client flows, admin consent — must be set for the Windows path to work.

IncorrectConfiguration is MSAL’s catch-all, and its surfaced text usually blames the redirect URI even when that’s correct. The same error also covers a malformed scope (AADSTS500011, resource api:/) and the self-token URI form (AADSTS90009) — see Expose an API above. Before re-checking the app registration, read the real AADSTS code from the device’s Microsoft-Windows-AAD/Operational log in Event Viewer (Get-WinEvent -LogName "Microsoft-Windows-AAD/Operational" -MaxEvents 20 and look at the resource: field). Sign-in logs in the Entra portal need a P1/P2 license, so the device event log is often the only place the true error appears.

The Arbium admin UI (admin-ui) is a Next.js console where designated admins sign in to view enrolled devices, manage the app blocklist, and inspect captures. It uses the authorization-code flow with PKCE (OIDC) for sign-in and then calls Microsoft Graph on-behalf-of the signed-in admin — purely delegated, never as the app itself. This shapes the settings below: web-platform redirect, client secret, and delegated Graph scopes. Admin authorization (who’s actually allowed in) is enforced separately, via the Arbium SCIM app and the Arbium Admins group covered later on this page — sign-in alone never grants access.

In Applications > App registrations > New registration:

Field Value
Name Arbium Admin (or similar)
Supported account types Accounts in this organizational directory only (single tenant)signInAudience = AzureADMyOrg
Redirect URI Platform = Web, URI = https://arbium.<your-domain>/admin/api/auth/callback

Confirm the final public Arbium hostname with Cloud Ops before registering. The Admin UI is path-mounted on the same hostname as edge-fns, so the callback includes /admin rather than a separate admin subdomain. For example:

https://arbium.contoso.com/admin/api/auth/callback

The URI Entra has on file must match https://<ingress.host>/admin/api/auth/callback exactly. Trailing slashes, port numbers, host casing, missing /admin, or http vs https differences all cause Entra to reject the callback with AADSTS50011.

Click Register. You now have a second Application (client) ID. The Directory (tenant) ID is the same one used for the agent app — both apps live in the customer’s single tenant.

Under Authentication:

  • Confirm the redirect URI you just registered is under the Web platform card (not “Mobile and desktop applications” or “Single-page application”).
  • Under Implicit grant and hybrid flows, both boxes (Access tokens, ID tokens) must be off. The admin app uses authorization-code flow with PKCE; implicit grant is disabled.
  • Under Advanced settings, Allow public client flows stays No (the admin app holds a confidential client secret).

Under Certificates & secrets > Client secrets > New client secret:

  • Description: use a recognizable purpose such as Arbium Admin.
  • Expires: choose a lifetime that fits the customer’s rotation policy and record the owner and renewal date.
  • After clicking Add, copy the Value column immediately. The Secret ID is not what you want.

Unlike the agent app (which doesn’t need a secret on Windows — WAM does it), this secret is required for the admin UI — the Next.js process exchanges authorization codes for tokens using it. Rotate by minting a new secret, sending the value to Cloud Ops over the secure channel, and they re-apply the Helm values; sessions stay alive until current tokens expire.

Under API permissions > Add a permission > Microsoft Graph > Delegated permissions, add exactly these and no application permissions:

Permission Why
openid OIDC sign-in
profile OIDC sign-in (display name)
email OIDC sign-in (UPN / email claim)
offline_access Reserved — refresh-token path not used yet but harmless to include
User.Read.All Lists enrolled users on the /users page. Requires admin consent.
DeviceManagementManagedDevices.Read.All Lists Intune-managed devices on the dashboard. Requires admin consent.

Entra’s UI may suggest the Application version of User.Read.All and DeviceManagementManagedDevices.Read.All when you search for *.All scopes. Pick the Delegated row, not Application. The admin UI calls Graph as the signed-in admin, not as the app — adding the Application versions does no harm but they’re unused and add noise to consent screens.

After adding all six, click Grant admin consent for <tenant>. All six rows should show Granted for <tenant> with green checks. Without admin consent on the two *.All scopes, sign-in returns consent_required and the dashboard pages can’t load Graph data.

5. Token configuration — no groups claim required for production

Section titled “5. Token configuration — no groups claim required for production”

Production Admin UI authorization uses SCIM-synced group membership, not the token groups claim. You do not need to add a groups claim for normal deployments.

Only add a groups claim if Cloud Ops explicitly asks to use the legacy token-groups fallback mode. In that fallback, add Security groups with Group ID under both ID and Access tokens.

In Entra > Groups > New group, create two Security groups (Membership type: Assigned):

Group Put in it Used for Hand to Cloud Ops as
Arbium Admins the people who manage the fleet opening the admin console scim.scimAdminGroupIds
Arbium Users everyone whose device runs the agent who Arbium accepts captures from; also the group you scope the app install to in Intune scim.scimUserGroupIds

Capture the Object ID of each group (Groups → the group → Overview). A user must be a member of Arbium Users for Arbium to accept their captures (once Cloud Ops enables the user gate), and a member of Arbium Admins to reach the console — non-members who sign in land on /forbidden.

Tip — keep “has the app” and “is in Arbium” in sync. Scope the agent app deployment in Intune to the same Arbium Users group. Then a single membership change both installs the agent on someone’s device and provisions their Arbium account; removing them reverses both.

SCIM provisioning does not run on the Agent or Admin app. Those are App Registrations, and Entra only offers automatic (SCIM) provisioning on non-gallery enterprise apps. If you open the Provisioning tab on the Arbium Admin app you’ll see “automatic provisioning is not supported” with Get started greyed out — that is expected, not a misconfiguration. So provisioning lives in its own dedicated app.

After Cloud Ops deploys Arbium, they will give you:

Tenant URL: https://<arbium-host>/scim/v2
Secret Token: <SCIM bearer token>

Then:

  1. Enterprise applications > New application > Create your own application.

  2. Name: Arbium SCIM.

  3. Choose “Integrate any other application you don’t find in the gallery (Non-gallery)”Create.

  4. Open the new app → ProvisioningGet started (clickable now) → set Provisioning Mode = Automatic.

  5. Under Admin Credentials, paste the Tenant URL and Secret Token → Test Connection (it should succeed).

  6. Under Mappings, keep user and group provisioning enabled. In both the user and group mapping, the critical row is:

    customappsso Attribute: externalId
    Microsoft Entra ID Attribute: objectId

    Do not map externalId from mailNickname, userPrincipalName, mail, or a display name. Arbium uses externalId as the stable Entra Object ID for login and group authorization — mapping anything else silently breaks sign-in and ingest enforcement. Also confirm group members is enabled/included.

  7. Under Users and groups, assign both security groups you created — Arbium Admins and Arbium Users. Assigning a group provisions the group and its members.

  8. Start provisioning and wait for the initial cycle (the first sync can take up to ~40 min).

Arbium only accepts a user’s captures, and only grants admin access, after that user (and the relevant group membership) has been provisioned through SCIM. OIDC sign-in alone is not enough.

For the Helm chart’s OIDC verifier — forward to Cloud Ops over your secure channel:

  • Directory (tenant) ID — the tenant GUID.
  • Application (client) ID of the Arbium Agent app — the app reg GUID. Both the issuer audience and the agent’s EntraClientId reference it.
  • Cloud hostlogin.microsoftonline.com, or login.microsoftonline.us if you are on a sovereign cloud.

Cloud Ops sets these in the Helm deployment’s OIDC configuration. The chart passes the issuer URL, audience, and RS256 algorithm to the backend; no manual database configuration is required.

Always send Cloud Ops:

  • Object ID of the Arbium Users group → scim.scimUserGroupIds (the capture/ingest allowlist).

If the Admin UI is in scope, also send Cloud Ops:

  • Application (client) ID of the Arbium Admin app.
  • Client secret value of the Arbium Admin app.
  • Object ID of the Arbium Admins group → scim.scimAdminGroupIds.
  • The Arbium hostname you used in the Admin UI Redirect URI (so Cloud Ops can confirm it matches ingress.host and /admin/api/auth/callback).

Cloud Ops puts these in the admin.entra.*, admin.secrets.data.*, scim.scimAdminGroupIds, and scim.scimUserGroupIds Helm values.

For the Windows config script — keep alongside the URL you will receive from Cloud Ops at handoff:

  • Tenant ID
  • Client ID of the Arbium Agent app (not the admin app — the agent does not use the admin app at all)
  • Application ID URI (typically api://<agent-client-id>)
  • Cloud host (only if non-default)

The Windows agent does not need a client secret — it uses the WAM broker bound to the device’s Primary Refresh Token instead. The admin-UI client ID and secret never reach managed devices.

2. Policy management. You can start this as soon as Cloud Ops returns the captures-endpoint URL.