Runbooks / Admin Ui

IdentityMesh Admin UI

The Admin UI is the Angular-based administration portal for IdentityMesh. It’s installed by the MSI as an IIS site alongside the Admin API and is the primary operator interface — connector configuration, schedule management, role assignments, run history, and audit views.

Build

npm install
npx ng build --configuration production

Output: dist/now-ui-dashboard-pro-angular/

The production build produces hashed static files (JS bundles, CSS, assets) suitable for deployment to any web server.

Deployment

The Admin UI is a static single-page application (SPA). It must be served by a web server such as IIS, nginx, or any static file host.

MSI Install

When installed via the IdentityMesh MSI (AdminUI feature), files are placed in C:\Program Files\IdentityMesh\ui\. The installer automatically:

  1. Creates an IIS site (IdentityMesh Admin Portal) on the configured port (default 4200) if IIS is available.
  2. Writes assets/config.json with the API URL (http://localhost:5100).
  3. Creates a desktop shortcut to the Admin Portal.

Manual IIS Configuration

If IIS was not available during install, or for custom setups:

  1. Create a new IIS website pointing to C:\Program Files\IdentityMesh\ui\.
  2. Set the default document to index.html.
  3. The UI uses hash-based routing (/#/), so no URL rewrite rules are needed.
  4. Edit assets/config.json if the API is on a different server.

API URL Configuration

The UI loads its API URL at runtime from assets/config.json. This file is written automatically by the installer’s DbSetup step.

Runtime config (assets/config.json):

{
  "apiUrl": "http://localhost:5100"
}

If config.json is missing or has no apiUrl, the UI falls back to relative URLs (same-origin requests). The AppConfigService loads this file via APP_INITIALIZER before the app bootstraps.

For separate-server deployments (UI and API on different machines), edit config.json to point to the remote API:

{
  "apiUrl": "http://api-server.domain.com:5100"
}

Environment files (used as fallback defaults):

Authentication

The UI uses Windows Integrated Authentication (Negotiate). All API requests include { withCredentials: true } via an AuthInterceptor. The IIS site hosting the UI must have Windows Authentication enabled.

Features

The Admin UI provides management interfaces for:

Routing

The UI uses hash-based routing (useHash: true) for SPA compatibility without server-side URL rewriting. All routes are under /#/.

Authentication modes

The Admin UI supports two authentication modes, selected via the runtime config file assets/config.json:

ModeWhen to useHow the user signs in
negotiate (default)On-prem / domain-joined deployments behind IIS or a reverse proxy that handles Windows Integrated Authentication.Browser sends Kerberos / NTLM credentials transparently.
jwtCloud / hybrid deployments where the customer wants Entra-issued bearer tokens.MSAL redirect to Entra; user signs in with their Entra account.

Negotiate mode (default)

No additional configuration required. The Admin API gates everything on RequireAuthorization() against the Negotiate scheme; the UI just issues HTTP requests with withCredentials: true and the proxy handles SPNEGO.

JWT / Entra mode

In assets/config.json (a runtime-loaded file the UI reads on startup):

{
  "apiBaseUrl": "https://identitymesh-api.contoso.com",
  "auth": {
    "mode": "jwt",
    "tenantId": "<entra tenant guid>",
    "clientId": "<this-app's-Entra-app-registration-client-id>",
    "redirectUri": "https://identitymesh-ui.contoso.com/",
    "postLogoutRedirectUri": "https://identitymesh-ui.contoso.com/",
    "apiScope": "api://identitymesh-api/access_as_user",
    "multitenant": false
  }
}

Setup steps:

  1. Register a new app in Entra ID (separate from the Admin API app). Type: Single-page application. Redirect URI: the UI’s public URL (e.g. https://identitymesh-ui.contoso.com/).
  2. Under API permissions, grant delegated access to the IdentityMesh API app’s access_as_user (or equivalent) scope.
  3. Copy the Application (client) ID into auth.clientId.
  4. Set auth.mode to jwt and fill the rest of the block.

When auth.multitenant is true, the UI uses the common authority and Entra prompts users to choose their tenant. The API side must independently widen Authentication:Jwt:Authority or ValidateIssuer to accept multi-tenant tokens; until that happens, multi-tenant in the UI alone won’t pass API-side validation.

The MSAL interceptor automatically attaches the user’s access token to outbound calls to apiBaseUrl. No code changes required to per-feature service classes.

Switching modes

Mode is determined at startup. To change modes:

  1. Update assets/config.json on the deployed UI host.
  2. Hard-refresh the browser (or close + reopen the tab) so the updated config is fetched.

The Admin API can run with both schemes simultaneously (the SmartAuth policy scheme routes per request based on Authorization Bearer header presence). A site running JWT-mode UI will work against an API configured for either Negotiate or JWT (or both).

Localization (i18n)

The UI uses Angular’s built-in @angular/localize for translation. Phase 1 ships the build pipeline + a small set of representative strings extracted (sign-in flow, navbar). Most other strings remain hard-coded English; extracting them is per-PR cleanup work as features ship.

Supported locales

LocaleFile
en-US (source)src/locale/messages.xlf
fr-FRsrc/locale/messages.fr.xlf (stub — copy of source pending real translations)

Add additional locales by:

  1. Copying src/locale/messages.xlf to src/locale/messages.<locale>.xlf.
  2. Translating the <source> strings into <target> elements.
  3. Registering the locale in angular.json under projects.now-ui-dashboard-pro-angular.i18n.locales.

Building a localized bundle

npx ng build --configuration=production --localize

Produces a per-locale subdirectory under dist/now-ui-dashboard-pro-angular/ (one for en-US, one for fr-FR, etc.). Serve each locale from its own URL prefix via your web server’s URL rewriting rules.

Adding new translatable strings

Mark them in templates with the i18n attribute and a unique identifier:

<h2 i18n="@@dashboard.title">Dashboard</h2>
<button i18n="@@dashboard.refreshButton" aria-label="Refresh"
        i18n-aria-label="@@dashboard.refreshAriaLabel">
  Refresh
</button>

Re-run npx ng extract-i18n --output-path=src/locale --format=xlf to refresh messages.xlf. Translators add the new <trans-unit> entries to each per-locale file.