Agent DocsDeveloper documentation
Admin Guide

Identity & Users

IdP configuration, user provisioning, and role management

Admin Guide: Identity and User Management

This guide is for platform administrators who manage identity providers, user provisioning, roles, groups, and sessions in the Admin Console.

The platform uses a hybrid identity model: authentication is always delegated to an external Identity Provider (IdP), while the platform maintains local user records for role assignment, entitlements, activity tracking, and cost attribution.

Where to manage: Admin Console > Tenant Manager (/admin/tenants) > Identity tab, and Admin Console > User Directory (/admin/users).


Table of Contents


Overview: Hybrid IdP Model

The platform never stores or manages user credentials directly. Instead, each tenant configures one or more external IdPs to handle authentication:

User visits platform
    |
    v
Redirected to tenant's IdP (Keycloak, Azure AD, or OIDC provider)
    |
    v
User authenticates at IdP
    |
    v
Redirected back with OIDC authorization code
    |
    v
Platform exchanges code for ID token + access token
    |
    v
Platform extracts claims: sub, groups, roles, email, name
    |
    v
Platform looks up PlatformUser by sub + tenantId
    |
    +-- Found: update lastLogin, refresh groups (JIT), return session
    +-- Not found: create PlatformUser, assign default role, return session

The IdP is the source of truth for credentials and group memberships. The platform is the source of truth for platform-specific role assignments, agent entitlements, and activity/cost tracking.


Tenant IdP Configuration

Each tenant configures its own IdP. Navigate to Admin Console > Tenant Manager > [Tenant] > Identity tab.

Supported Providers

ProviderValueBest For
KeycloakkeycloakEU data-sovereign tenants, self-hosted identity
Azure AD / Entra IDazure-adMicrosoft ecosystem enterprises
Generic OIDCoidc-genericAny OIDC-compliant provider (Okta, Auth0, Ping, etc.)

TenantIdpConfig Schema

interface TenantIdpConfig {
  tenantId: string;
  provider: 'keycloak' | 'azure-ad' | 'oidc-generic';
  provisioningMode: 'scim' | 'jit' | 'bundled-keycloak';
  oidcConfig: {
    issuerUrl: string;
    clientId: string;
    // clientSecret stored in Vault, not in this config
    scopes: string[];
    claimMappings: {
      groups: string;     // JWT claim path for groups
      roles: string;      // JWT claim path for roles
      tenantId: string;   // JWT claim path for tenant ID
    };
  };
  roleMappingStrategy: 'idp-groups' | 'idp-roles' | 'manual';
  roleMappings?: { group: string; role: 'consumer' | 'builder' | 'admin' }[];
  sessionConfig: {
    maxDurationMinutes: number;
    concurrentSessionLimit?: number;
  };
  scimEndpoint?: string;  // Only if provisioningMode == 'scim'
}

Configuration Steps

  1. Select provider: Choose Keycloak, Azure AD, or Generic OIDC.
  2. Enter OIDC settings: Issuer URL, Client ID, Scopes.
  3. Store client secret: The client secret is stored in Vault. Enter it via the secure input field (it will be masked after saving).
  4. Configure claim mappings: Map JWT claims to platform fields (groups, roles, tenant ID).
  5. Select provisioning mode: SCIM 2.0, JIT, or Bundled Keycloak.
  6. Set up role mappings: Map IdP groups to platform roles.
  7. Configure session policy: Set max duration and concurrent session limits.
  8. Test the connection: Click "Test IdP Connection" to perform OIDC discovery and validate the configuration.

OIDC Settings

Required Fields

FieldDescriptionExample
Issuer URLThe OIDC issuer URL. Must support /.well-known/openid-configuration.https://login.microsoftonline.com/{tenant-id}/v2.0
Client IDThe OAuth 2.0 client ID registered in the IdP.a1b2c3d4-e5f6-7890-abcd-ef1234567890
ScopesOIDC scopes to request. Must include openid.["openid", "profile", "email", "groups"]

Provider-Specific Defaults

Keycloak:

{
  "issuerUrl": "https://keycloak.example.com/realms/my-realm",
  "scopes": ["openid", "profile", "email", "groups"],
  "claimMappings": {
    "groups": "groups",
    "roles": "realm_access.roles",
    "tenantId": "tenant_id"
  }
}

Azure AD / Entra ID:

{
  "issuerUrl": "https://login.microsoftonline.com/{azure-tenant-id}/v2.0",
  "scopes": ["openid", "profile", "email", "GroupMember.Read.All"],
  "claimMappings": {
    "groups": "groups",
    "roles": "roles",
    "tenantId": "tid"
  }
}

Generic OIDC:

{
  "issuerUrl": "https://your-provider.example.com",
  "scopes": ["openid", "profile", "email"],
  "claimMappings": {
    "groups": "custom:groups",
    "roles": "custom:roles",
    "tenantId": "custom:tenant"
  }
}

Claim Mappings

Claim mappings tell the platform which JWT claims contain the user's groups, roles, and tenant identifier. These are configured per tenant because different IdPs use different claim names.

Configuration

claimMappings: {
  groups: string;     // e.g. 'groups' or 'cognito:groups'
  roles: string;      // e.g. 'roles' or 'realm_access.roles'
  tenantId: string;   // e.g. 'tenant_id' or 'tid' or 'custom:tenant'
}

Common Claim Paths by Provider

ProviderGroups ClaimRoles ClaimTenant Claim
Keycloakgroupsrealm_access.rolestenant_id (custom)
Azure ADgroups (GUIDs) or securityGroupsroles (App Roles)tid
Oktagroupsrolesorganization
Auth0https://myapp/groups (custom namespace)https://myapp/rolesorg_id

Testing Claim Mappings

Use the "Test mapping" button in the Identity tab. It accepts a sample JWT payload and shows what platform role and groups would be extracted:

Sample JWT input: { "sub": "user123", "groups": ["eng-team"], "roles": ["developer"], "tid": "tenant-1" }

Result:
  - Platform groups: ["eng-team"]
  - Platform role mapping: "eng-team" -> consumer (from role mappings)
  - Tenant ID: "tenant-1"

User Provisioning Modes

The provisioning mode determines how user records are created and kept current in the platform.

SCIM 2.0 Sync (Recommended)

Best for: Production deployments where builders need to browse real IdP groups when configuring agent entitlements.

The IdP pushes user and group changes to the platform in real time via SCIM 2.0 endpoints.

How it works:

  1. Configure the IdP to push to the platform's SCIM endpoint: POST /api/scim/v2/Users, PATCH /api/scim/v2/Users/:id, DELETE /api/scim/v2/Users/:id, GET /api/scim/v2/Groups.
  2. The platform maintains a synchronized, browsable cache of all users and groups.
  3. When a user is deprovisioned in the IdP, the SCIM DELETE deprovisions them in the platform immediately.
  4. Group membership changes propagate without requiring user re-login.

Advantages:

  • Agent entitlement group pickers show real, up-to-date IdP groups.
  • User deprovisioning is immediate (no waiting for next login).
  • Group changes take effect without requiring affected users to re-authenticate.

Configuration:

{
  "provisioningMode": "scim",
  "scimEndpoint": "https://platform.example.com/api/scim/v2"
}

JIT Provisioning (Just-In-Time)

Best for: Simpler deployments where SCIM is not available.

User records are created on first login from JWT claims. Groups are refreshed on each subsequent login.

How it works:

  1. User logs in via OIDC.
  2. Platform extracts sub, email, name, groups, roles from the JWT.
  3. If no PlatformUser record exists for this sub + tenantId, one is created.
  4. If a record exists, lastLogin and groups are updated from the JWT.

Limitations:

  • Groups only update when users log in. If a user is removed from a group in the IdP, they retain access until their next login.
  • The group picker in Agent Designer only shows groups that have been seen via user logins (not a complete list).
  • User deprovisioning requires explicit admin action in the platform (or the user's next login attempt fails at the IdP).

Bundled Keycloak

Best for: Standalone or proof-of-concept deployments where no external IdP exists.

The platform ships its own Keycloak instance for identity management.

How it works:

  1. The platform deploys a Keycloak instance as part of its infrastructure.
  2. Users, groups, and credentials are managed directly in Keycloak.
  3. The platform connects to this Keycloak instance via OIDC, same as any external IdP.

Configuration:

{
  "provisioningMode": "bundled-keycloak",
  "provider": "keycloak",
  "oidcConfig": {
    "issuerUrl": "https://keycloak.platform-internal.svc/realms/platform"
  }
}

Role Management

Platform Roles

The platform has three roles, each granting access to specific applications:

RoleApplicationsCapabilities
consumerPortal onlyChat with agents, approve/reject HITL requests, view history
builderPortal + StudioCreate agents, configure access control, deploy, test, monitor
adminPortal + Studio + Admin ConsoleManage tenants, users, policies, platform health, compliance

Role Assignment Strategies

Configure via roleMappingStrategy in the tenant IdP config:

Strategy: idp-groups -- Map IdP groups to platform roles.

{
  "roleMappingStrategy": "idp-groups",
  "roleMappings": [
    { "group": "agentic-admins", "role": "admin" },
    { "group": "agentic-builders", "role": "builder" },
    { "group": "all-staff", "role": "consumer" }
  ]
}

Evaluation order: The most privileged matching role wins. If a user is in both agentic-builders and all-staff, they receive the builder role.

Strategy: idp-roles -- Map IdP role claims directly to platform roles.

The platform reads the roles claim from the JWT and maps matching values. Useful when the IdP natively supports application roles (e.g., Azure AD App Roles).

Strategy: manual -- Roles are assigned by an admin in the User Directory.

No automatic mapping from IdP. Every user starts with the default role (configurable, typically consumer). Admins manually assign builder or admin roles via Admin Console > User Directory.

Changing a User's Role

  1. Navigate to Admin Console > User Directory (/admin/users).
  2. Click on the user.
  3. In the user detail panel, change the "Platform Role" dropdown.
  4. Save. The change takes effect on the user's next API request (session is refreshed).

The role change source is recorded in the audit trail: "Role changed from consumer to builder by admin-user-1 on 2025-06-15."


Group Management

Where Groups Come From

Groups originate in the IdP and are synchronized to the platform. The platform does not create or manage groups; it reads them from the IdP.

SourceSync MechanismFreshness
SCIM 2.0IdP pushes changesReal-time
JITExtracted from JWT on loginUpdated per login
Bundled KeycloakManaged in Keycloak admin consoleImmediate (same infrastructure)

Default Groups

The platform ships with a default set of groups for mock/development mode:

GroupDescription
engineeringEngineering and development team
hr-teamHuman resources team
financeFinance and accounting team
executivesC-suite and executive leadership
all-staffAll employees (default group)

In production, groups are populated from the IdP and will reflect the actual organizational structure.

Groups and Agent Entitlements

Groups are the primary mechanism for Dimension 1 (User -> Agent) access control. When a builder configures an agent with allowedGroups: ["hr-team"], only users whose IdP group membership includes hr-team can see and use the agent.

The group picker in Agent Studio's Access tab is populated from the GET /api/groups endpoint, which returns IdpGroupCache entries:

interface IdpGroupCache {
  tenantId: string;
  groupName: string;
  memberCount: number;
  lastSynced: string;
}

For SCIM provisioning, this cache is always up to date. For JIT provisioning, it contains only groups seen in user logins.

Viewing Group Memberships

Admin Console > User Directory > select a user > "Group Memberships" section shows:

  • List of IdP groups the user belongs to
  • Last synced timestamp per group
  • Source indicator (SCIM-synced or JIT-cached)

Session Management

Session Configuration

Sessions are configured per tenant in the IdP config:

sessionConfig: {
  maxDurationMinutes: number;      // Default: 480 (8 hours)
  concurrentSessionLimit?: number; // Optional: max active sessions per user
}

Recommended Session Durations by Role

RoleRecommended Max DurationRationale
consumer480 minutes (8 hours)Standard workday access
builder240 minutes (4 hours)Elevated privileges, shorter sessions
admin60 minutes (1 hour)Highest privileges, strict session limits

Session Lifecycle

  1. Creation: Session starts when user completes OIDC login. Contains: userId, role, tenantId, groups, permissions, idpSource.
  2. Heartbeat: Session validity is checked every 60 seconds on active clients.
  3. Expiry: Session expires after maxDurationMinutes from creation. User is redirected to the login page with a "Session expired" message.
  4. Forced Logout: Admins can terminate all sessions for a user via User Directory > "Sign out all sessions."
  5. IdP Logout: On user logout, the platform clears the local session and redirects to the IdP's logout endpoint for single sign-out.

Concurrent Session Limits

If concurrentSessionLimit is set, the platform enforces a maximum number of active sessions per user. When the limit is reached, the oldest session is terminated.

Viewing Active Sessions

Users can view their own sessions at Account Settings (/settings) > "Active Sessions" section. Each session shows:

  • Device/browser information
  • IP address
  • Last activity timestamp
  • "Current session" indicator

Users can click "Sign out all other sessions" to terminate all sessions except the current one.

Admins can view sessions for any user via User Directory > user detail > "Activity" section.


User Directory Operations

The User Directory at /admin/users provides a comprehensive view of all provisioned users.

User Table Columns

ColumnDescription
Display NameUser's full name from IdP
EmailEmail address from IdP
IdP SourceBadge: Keycloak / Azure AD / OIDC
Platform RoleBadge: consumer / builder / admin
GroupsChip list of IdP groups
ProvisioningSCIM / JIT / Local
Statusactive / suspended / deprovisioned
Last LoginTimestamp of most recent login

Available Actions

ActionDescriptionAPI Endpoint
Change roleChange a user's platform rolePUT /api/admin/users/:id/role
SuspendBlock the user from accessing the platformPOST /api/admin/users/:id/suspend
ReactivateRestore access for a suspended userPOST /api/admin/users/:id/reactivate
View entitlementsSee which agents this user can access (Dim 1 reverse lookup)GET /api/admin/users/:id/agents
Open in IdPDeep link to the IdP admin console for this userExternal link

Important: Suspending a user in the platform does not modify their IdP account. It only blocks platform access. To fully deprovision a user, deactivate them in the IdP as well.

Reverse Lookups

From a user record, you can answer:

  • "Which agents can this user access?" -- Lists all agents where the user matches entitlements (Dimension 1).
  • "What role does this user have?" -- Shows the current platform role and its source (mapped from IdP group or manually assigned).

From an agent record (in Agent Registry), you can answer:

  • "Who can access this agent?" -- Lists all users whose group/role/ID matches the agent's entitlements.

SCIM 2.0 Integration

Platform SCIM Endpoints

The platform exposes the following SCIM 2.0 endpoints for IdP provisioning:

OperationEndpointDescription
Create userPOST /api/scim/v2/UsersCalled when a user is created in the IdP
Update userPATCH /api/scim/v2/Users/:idCalled when user attributes change
Deprovision userDELETE /api/scim/v2/Users/:idCalled when a user is removed from the IdP
List groupsGET /api/scim/v2/GroupsCalled by IdP to sync group information

Configuring SCIM in the IdP

Keycloak:

  1. Install the SCIM provisioning plugin for Keycloak.
  2. Configure the SCIM client to point at the platform's SCIM endpoint.
  3. Set the Bearer token for authentication (generated in the platform's tenant configuration).

Azure AD / Entra ID:

  1. In the Azure portal, navigate to your Enterprise Application.
  2. Go to Provisioning > Automatic provisioning.
  3. Set the Tenant URL to https://platform.example.com/api/scim/v2.
  4. Set the Secret Token to the SCIM bearer token from the platform.
  5. Test the connection and start provisioning.

SCIM Status Monitoring

In the Tenant Manager > Identity tab, the SCIM section shows:

  • Last sync timestamp: When the last SCIM event was received.
  • Sync status: Active / Error / Stale (no events in 24 hours).
  • Error log: Recent SCIM errors (authentication failures, schema mismatches, etc.).

Troubleshooting IdP Issues

"Session Expired" on Login

Cause: The session maxDurationMinutes has been reached.

Resolution: This is expected behavior. The user must re-authenticate. If the duration is too short, increase maxDurationMinutes in the tenant's session configuration.

"Account Suspended" on Login

Cause: An admin has suspended the user in the platform.

Resolution: Navigate to User Directory, find the user, and click "Reactivate" if appropriate. Check the audit log for who suspended the account and why.

"IdP Unreachable" on Login

Cause: The platform cannot reach the configured IdP's OIDC discovery endpoint.

Resolution:

  1. Verify the Issuer URL is correct and accessible from the platform's network.
  2. Check network connectivity (DNS, firewalls, proxy settings).
  3. Verify the IdP service is running.
  4. Use "Test IdP Connection" in the Identity tab to diagnose.

Users Not Seeing Updated Groups

Cause (JIT mode): Groups are only refreshed on login. The user has not logged in since the group change.

Resolution: Ask the user to log out and log back in. For real-time group updates, switch to SCIM 2.0 provisioning.

Cause (SCIM mode): SCIM sync may have failed.

Resolution: Check the SCIM status in the Identity tab. Look for errors in the SCIM error log. Verify the SCIM endpoint is reachable from the IdP.

Role Mapping Not Working

Cause: The claimMappings.roles or claimMappings.groups path does not match the actual JWT claim structure.

Resolution:

  1. Decode a user's JWT token (use jwt.io or similar).
  2. Find the actual claim path for groups and roles.
  3. Update the claim mappings in the tenant's IdP configuration.
  4. Use "Test mapping" to verify the updated configuration against a sample JWT.

SCIM Provisioning Failing

Cause: Authentication failure, schema mismatch, or network issue.

Resolution:

  1. Verify the SCIM bearer token has not expired.
  2. Check the SCIM error log in the Identity tab for specific error messages.
  3. Ensure the IdP's SCIM client is configured with the correct endpoint URL.
  4. Verify the IdP is sending SCIM payloads in the expected format (SCIM 2.0 schema).

User Cannot Access Expected Application

Cause: The user's platform role does not grant access to the requested application.

Resolution: Verify the user's role:

  • consumer can only access Portal.
  • builder can access Portal and Studio.
  • admin can access all three applications.

Check the role mapping: is the user in the correct IdP group? Use the User Directory to inspect the user's current role and groups.


Related Documentation