Skip to content

People Picker — IDP Directory Browse

Overview

Cesivi's people picker can fan-out search queries to external OIDC identity providers (Keycloak, Entra ID, Okta, Authentik), returning remote users and groups alongside local Cesivi users. When configured, typing in a user field on any list form triggers a parallel search across all enabled providers. Results from different providers appear with a colored provider badge (e.g., keycloak-corp) so users can distinguish identity sources at a glance.


Prerequisites

  • PLAN-1613: multi-provider config shape must be in appsettings.json
  • Each provider must have a dedicated admin/service-account client with user-read permissions:
  • Keycloak: realm-managementview-users, view-groups
  • Entra ID: Microsoft Graph User.Read.All, GroupMember.Read.All
  • Okta: API token with okta.users.read, okta.groups.read
  • Authentik: API token with user/group read scope

Configuration

Add a DirectoryBrowse sub-section inside each provider entry in appsettings.json:

"Cesivi": {
  "Identity": {
    "OidcProviders": [
      {
        "Name": "keycloak-corp",
        "Enabled": true,
        "Authority": "https://sso.example.com/realms/corp",
        "ClientId": "cesivi-webui",
        "ClientSecret": "...",
        "DirectoryBrowse": {
          "Enabled": true,
          "ClientId": "cesivi-admin",
          "ClientSecret": "...",
          "TimeoutSeconds": 5,
          "PageSize": 20
        }
      },
      {
        "Name": "entra-corp",
        "Enabled": true,
        "Authority": "https://login.microsoftonline.com/{tenantId}/v2.0",
        "ClientId": "...",
        "ClientSecret": "...",
        "DirectoryBrowse": {
          "Enabled": true,
          "ClientId": "...",
          "ClientSecret": "..."
        }
      }
    ]
  }
}

Fields:

Field Required Default Description
Enabled Yes false Enable directory browse for this provider
ClientId Yes Admin client ID (may differ from the login client ID)
ClientSecret Yes Admin client secret
TimeoutSeconds No 5 Per-provider fan-out timeout
PageSize No 20 Max results returned per provider per query

How It Works

  1. User types ≥ 2 characters into a User field picker.
  2. Cesivi fans out to all DirectoryBrowse.Enabled providers in parallel using a service-account token.
  3. Results are merged: local users (from the Cesivi user store) come first, then remote users, deduplicated by claims key.
  4. A provider badge appears on any result whose login name encodes a provider (i:0e.t|{providerName}|{subject}).
  5. If a provider is slow (exceeds TimeoutSeconds) or returns an error, it is soft-failed — the picker returns whatever other providers and local results are available. No error is shown to the user.

Provider Detection

Cesivi auto-detects the IDP type from the Authority URL:

Pattern Provider Notes
/realms/ in URL Keycloak Uses admin REST API
microsoftonline.com Entra ID Uses Microsoft Graph /v1.0
.okta.com Okta Flat groups (SupportsGroupHierarchy=false)
/application/o/ Authentik Uses Authentik REST API v3

Provider Badges

When a suggestion or chip comes from a remote OIDC provider, a small badge shows the provider name:

  • Suggestions dropdown: badge appears inline with the display name
  • Chips (selected users): badge appears inside the chip, right of the display name

Badge styling is in wwwroot/css/modern/forms.css (.sp-picker-provider-badge). The badge uses a blue-tint background by default; high-contrast / dark themes inherit adjusted colors.


Operator Checklist

  • [ ] Each provider's admin client has been granted the required read permissions in the IDP
  • [ ] DirectoryBrowse.ClientId / ClientSecret are populated in appsettings.json (or secrets manager)
  • [ ] TimeoutSeconds is set appropriately for your network latency (≥ 3s for remote IDPs)
  • [ ] Tested by typing a known remote user's name into a User field and seeing their result with badge

Troubleshooting

Symptom Likely Cause Fix
No remote results DirectoryBrowse.Enabled is false or missing Set to true and restart
Remote results vanish intermittently TimeoutSeconds too low Increase to 8–10s
"Alice" returns 0 results from Entra Graph scopes not granted Add User.Read.All to the admin app registration
Badge missing on provisioned OIDC user LoginName not in OIDC format Check EnsureUser created the user with i:0e.t|… login
Keycloak returns 401 Admin client secret expired Rotate the secret in Keycloak and update config

PLAN-1618 (People-Picker IDP Directory Browse). Finalized in PLAN-1619.