Appearance
Users and access reference
The Studio Explorer folder Security > Users & Access contains the screens that manage people: their accounts, their standing exceptions, their sessions, the applications they may enter, the password rules they follow, authority they hand to others, their own preferences and the trail of what happened to their accounts. Roles and the permissions given to roles are in Permission screens reference; the sign-in pages are in Identity.
Conventions used on this page. Every request carries X-Tenant-Id; X-Actor names the caller (default anonymous). Account, role and policy mutations require the AUTHOR capability, with artifact type user for accounts and role for role assignments; reads are open. Errors from account endpoints are plain {"status", "error", "message"} bodies, and from authoring endpoints {"code", "message", "detail"}. The CLI has no dedicated commands for these screens; use erp api get|post|put|delete <path> --tenant <id> --body <json-or-@file> after erp login (Sign in and environments).
Users
The Users screen lists the workspace's accounts and is the place to create, edit, lock, archive and delete them, assign roles, issue temporary passwords, manage multi-factor authentication and trust devices. Workspace administrators use it.
Where to find it. Security > Users & Access > Users. Page key users.
Key concepts.
| Term | Definition |
|---|---|
| Username | The unique sign-in name. Sign-in also accepts the account's email or mobile number. |
| Status | One of eight values (see Statuses and lifecycle). |
| Archived | A marker separate from status. An archived account keeps its status and shows an "Archived" chip. |
| Primary role | The one role of a person flagged primary. Setting a new primary role clears the previous flag. |
| Role window | Optional effective-from and expiry dates on one role assignment. Outside the window the role is ignored. |
| Trusted device | A device the person has signed in from and an administrator or the person marked trusted; it skips the MFA prompt. |
Fields and options.
Toolbar: Import, Export CSV, Create User. Search placeholder "Search by username, email or mobile". The status filter offers the eight statuses. The list is paginated on the server, 25 rows by default. Columns: User (username with email), Mobile, Status (chip, plus "Archived"). Empty state "No users match this search/filter."
Create User dialog:
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Username | Text | empty | Yes | Unique per workspace. |
| Password | Password | empty | Yes | Helper text "At least 8 characters". The real rules are the effective Password Policy. |
| Text | empty | No | Unique per workspace when given. | |
| Mobile | Text | empty | No | Unique per workspace when given. |
Create is disabled until username and password are filled. A new account is created with status ACTIVE, together with its profile and credential and its platform identity.
Expanded row (select a user), top to bottom:
| Section | Fields and buttons | Effect |
|---|---|---|
| Lifecycle buttons | Activate, Deactivate, Suspend, Lock, Unlock, Delete, Archive, Restore (only the ones that apply to the current status), Issue Temporary Password | See Statuses and lifecycle. |
| Roles | Multi-select Roles (placeholder "Add a role"; suggestions are the role catalog, free text is accepted), Save Roles | Replaces the person's whole role set. |
| Role Details (primary / effective / expiry) | One line per assignment with Primary Role chip, "From" and "Until" date chips and Remove; form Role name, Primary, Effective from, Expires, Add Role | Adds or replaces one assignment with its window. Unfiltered: assignments outside their window are still listed. |
| Profile | First name, Last name, Email, Mobile, Time zone, Save Profile | Saves profile then contact details. |
| Change Password | Current password, New password, Change Password | Self-service change. Success text "Password changed." |
| Multi-Factor Authentication (TOTP) | Enable MFA; after enrolment fields otpauth URI, Secret (manual entry), 6-digit code, Verify & Enable; when enabled the chip "MFA Enabled", Password to disable MFA, Disable MFA | See below. |
| Devices | Rows "browser on os", "last seen" with the time, chips Trusted, Revoked or Not trusted, buttons Trust or Revoke; paging at 10 per page | See below. |
Actions.
| Action | Effect | API |
|---|---|---|
| Create User | Creates the account | POST /api/v1/users body {username, password, email, mobile} |
| Save Profile | Updates profile and contact | PUT /api/v1/users/{id}/profile, PUT /api/v1/users/{id}/contact |
| Lifecycle buttons | Status transitions | POST /api/v1/users/{id}/activate, /deactivate, /lock, /unlock, /suspend, /archive, /restore; DELETE /api/v1/users/{id} |
| Issue Temporary Password | Generates a policy-compliant random password valid 24 hours, shown once in a dialog "Temporary Password Issued" with the warning "This is shown once and never stored in plaintext - copy it now. The account must change it within 24 hours or on next login, whichever comes first." (Copy, Done) | POST /api/v1/users/{id}/issue-temporary-password |
| Save Roles | Replaces the role set | PUT /api/v1/authoring/actor-roles/{username} body {"roles": [...]} |
| Add Role | Adds one assignment | POST /api/v1/authoring/actor-roles/{username}/roles body {role, isPrimary, effectiveAt, expiryAt} |
| Remove | Revokes one role | DELETE /api/v1/authoring/actor-roles/{username}/roles/{role} |
| Change Password | Self-service change | PUT /api/v1/users/{id}/password body {currentPassword, newPassword} |
| Import | Bulk create from CSV or XLSX | POST /api/v1/users/bulk-import (multipart field file) |
| Export CSV | Downloads users.csv for the current search and status filter (xlsx through the API) | GET /api/v1/users/export?format=csv&search=&status= |
| Enable MFA, Verify & Enable, Disable MFA | TOTP enrolment | POST /api/v1/users/{id}/mfa/enroll, /verify-enrollment body {code}, /disable body {currentPassword}; GET /api/v1/users/{id}/mfa/status |
| Trust, Revoke | Device trust | POST /api/v1/users/{id}/devices/{deviceId}/trust, /revoke; GET /api/v1/users/{id}/devices |
| Admin password reset (API only) | Sets a new password without the current one | POST /api/v1/users/{id}/reset-password body {newPassword} |
| Bulk status or role change (API only) | Applies one action to many users; each user succeeds or fails on its own | POST /api/v1/users/bulk-action body {ids, action, role} with action activate, deactivate, lock, unlock, assign-role or remove-role |
Role names typed or selected are resolved to the role's stable code before they are stored; text that matches no role is stored unchanged. Roles may also be listed and assigned by user id (GET and POST /api/v1/users/{id}/roles, DELETE /api/v1/users/{id}/roles/{role}).
Procedures.
Create an account with a temporary window for a role.
- Select Create User; enter Username
priya.nair, PasswordWelcome#2026x, Emailpriya.nair@example.com. Select Create. The user appears with statusACTIVE. - Expand the row. In Role name enter
Leave Manager, tick Primary, set Effective from2026-10-06and Expires2026-12-31, select Add Role. The line shows the chips "Primary Role", "From 06/10/2026" and "Until 31/12/2026". - Check with the Effective Permission Viewer.
Import users.
- Prepare a CSV with the header
username,password,email,mobile,roles. Roles are separated by semicolons inside the cell, for exampleEmployee;Leave Manager. Onlyusernameandpasswordare mandatory columns; column names are case-insensitive. - Select Import and choose the file (
.csvor.xlsx). - The dialog "Bulk Import Result" reads "8 of 10 row(s) created successfully, 2 failed." with one line per row: "Row 3", the username and a chip "OK" or the error.
Statuses and lifecycle.
| Status (database value) | Meaning | How it is entered |
|---|---|---|
ACTIVE (Active) | Can sign in. | Create, Activate, Unlock, password change or reset from Locked or PasswordExpired, automatic unlock after the lockout window |
PENDING_ACTIVATION (PendingActivation) | Created but not yet activated. | Provisioning paths |
INACTIVE (Inactive) | Switched off. | Deactivate, Restore of a deleted user |
LOCKED (Locked) | Blocked after repeated failures or by an administrator. | Lock, automatic lockout |
DISABLED (Disabled) | Switched off by an external source. | Provisioning paths |
SUSPENDED (Suspended) | Temporarily withheld. | Suspend |
PASSWORD_EXPIRED (PasswordExpired) | The password is older than the policy's expiry days. | Automatic at sign-in |
DELETED (Deleted) | Soft-deleted; the row is kept. | Delete |
| Operation | Allowed from | Result |
|---|---|---|
| Activate | PENDING_ACTIVATION, INACTIVE, DISABLED, SUSPENDED | ACTIVE |
| Deactivate | ACTIVE | INACTIVE |
| Suspend | ACTIVE | SUSPENDED |
| Lock | ACTIVE, INACTIVE, SUSPENDED | LOCKED |
| Unlock | LOCKED | ACTIVE; failed-attempt and lockout counters are cleared |
| Archive | any status except DELETED, not already archived | Status unchanged; archived marker set |
| Delete | any status except DELETED | DELETED; archived marker kept |
| Restore | archived or deleted | Archive and delete markers cleared. A deleted user returns as INACTIVE, never straight to ACTIVE. |
The screen offers Activate for the four activatable statuses, Deactivate and Suspend for ACTIVE, Unlock for LOCKED and Lock otherwise, Delete unless deleted, Restore when archived or deleted and Archive otherwise. A button the server rejects returns the message in the first row of the errors table.
Multi-factor authentication. Enrolment returns a 160-bit secret and the URI otpauth://totp/ERP:<username>?secret=...&issuer=ERP&digits=6&period=30 for an authenticator application. Entering the current 6-digit code and selecting Verify & Enable activates the credential. Once active, a sign-in from a device that is not trusted must complete a second step (see Identity). Disabling requires the account password. Devices: each sign-in records a device fingerprint; a trusted, non-revoked device skips the MFA step on its next sign-in, and the first sign-in from an unknown device sends a new-device alert. Empty state "No devices recorded yet - a device is captured the next time this user signs in."
Permissions. Reading the list needs no capability. Creating, editing, lifecycle actions, issuing temporary passwords, role changes, device administration, import and the bulk and admin-reset calls need AUTHOR on user (roles: role). Changing a password through PUT /api/v1/users/{id}/password needs no capability; proof of the current password is the gate. Export uses the same read posture as the list.
API.
| Method and path | Purpose |
|---|---|
GET /api/v1/users?pageIndex=0&pageSize=25&search=priya&status=ACTIVE | Page of users, body {rows, total}. A blank status means no filter. |
GET /api/v1/users/{id} | {user, profile} |
GET /api/v1/authoring/actor-roles/{username}/detail | Assignments with primary, effective and expiry |
bash
erp api get "/api/v1/users?search=priya&status=ACTIVE" --tenant 2
erp api post /api/v1/users --tenant 2 --body '{"username":"priya.nair","password":"Welcome#2026x","email":"priya.nair@example.com"}'
erp api post /api/v1/authoring/actor-roles/priya.nair/roles --tenant 2 --body '{"role":"Leave Manager","isPrimary":true,"expiryAt":"2026-12-31T00:00:00Z"}'Limits and behaviour. The list endpoint is paginated and limits are clamped to 1 to 500 rows (default 25). Account changes, password events and role changes by notification are recorded (see Audit Logs). Email notifications (welcome, password changed, account locked, activated, deactivated, role changed) are sent unless the person has opted out under Preferences.
Errors.
| Message | Cause | Fix |
|---|---|---|
| Cannot move user from Disabled to Locked (the form is "Cannot move user from X to Y" with the database status names) | The transition is not allowed from the current status (HTTP 409) | Use an operation listed in the transition table. |
| User "priya.nair" already exists for this tenant | Duplicate username (409) | Choose another username. |
| Email "x" is already in use for this tenant / Mobile "x" is already in use for this tenant | Duplicate contact (409) | Use another value or clear the field. |
| username is required | Blank username (400) | Enter it. |
| Password must be at least 8 characters (and the other policy messages) | Password breaks the effective policy (400) | See Password Policy. |
| This password was used recently - choose a different one | Password history (400) | Choose a new password. |
| Current password is incorrect | Wrong current password on change or MFA disable (401) | Re-enter it. |
| Invalid code | Wrong TOTP code on enrolment (401) | Enter the current 6-digit code. |
| Cannot archive a deleted user; User is already archived; User is not archived or deleted; User is already deleted | Archive, restore or delete in the wrong state (409) | Check the status and archived chip. |
| CSV file is empty; CSV header must include at least username and password columns; file is required | Bad import file (400) | Fix the file. |
| No user 99 for tenant 2 | Unknown id (404) | Reload the list. |
| Cannot manage another user's device | A person tried to change someone else's device through the self-service endpoint (403) | Use the administrator endpoint. |
Related. Roles, Identity, Password Policy, LDAP / SSO and provisioning.
User Overrides
A user override is a standing allow or deny for one person on one resource and action. It sits above the person's roles and below a temporary permission, so it is the way to make an exception for one person without changing a role.
Where to find it. Security > Users & Access > User Overrides. Page key user-permissions.
Fields and options.
| Field | Type or allowed values | Default | Required | Description |
|---|---|---|---|---|
| Actor | Text | empty | Yes | The username. Helper text "e.g. alice". |
| Resource | Select: employee, org_unit, job_classification, position | employee | Yes | The Studio list is fixed. The API accepts any resource string such as page:payroll-run. |
| Action | Select: create, read, update, delete, view, approve, reject, cancel, submit, clone, archive, restore, print, export, import, upload, download, share, assign, execute | create | Yes | |
| Effect | Select: allow, deny | deny | Yes | |
| Scope | Org unit select | (Global - no scope) | No | A scoped override applies when the person's org unit is that unit or below it. |
Add override is disabled while Actor is empty. Grid columns: Actor (with resource.action), Resource, Action, Effect, Scope ("Global" or "Org unit #12"). Icons: history and remove. Empty state "No overrides yet - add one above."
An override is identified by (actor, resource, action, org unit); saving the same combination replaces its effect. Precedence is described in Permissions - how an access decision is made: when any override matches, its decision is final for the person, a deny winning among several matching overrides.
API. GET /api/v1/user-permissions; PUT /api/v1/user-permissions body {actorSubject, resource, action, effect, orgUnitId}; DELETE /api/v1/user-permissions body {actorSubject, resource, action, orgUnitId}.
bash
erp api put /api/v1/user-permissions --tenant 2 --body '{"actorSubject":"alice","resource":"page:payroll-run","action":"view","effect":"allow"}'Permissions. AUTHOR on role. Overrides are versioned (entity type user_permission, key actor|resource|action|orgUnitId with * for tenant-wide) and written to the Permission Audit Log as user_permission operations update (set) and delete (clear).
Errors (HTTP 400). "actor is required"; "resource is required"; "action is required"; "effect must be one of [allow, deny]".
Sessions
The Sessions screen (titled "Active Sessions") lists the signed-in caller's own live sessions and ends them. It is a self-service screen: every session belongs to the current caller.
Where to find it. Security > Users & Access > Sessions. Page key sessions.
Key concepts.
| Term | Definition |
|---|---|
| Session | Created by a successful sign-in. The client receives an opaque random token (256 bits) sent as X-Session-Token; only its hash is stored. |
| Access token | A short-lived signed token (15 minutes) minted from the session for service-to-service calls; it carries the tenant, the actor and the session id. |
| Idle timeout | A session unused for this long is revoked at its next validation. Default 30 minutes. |
| Absolute timeout | A session ends this long after sign-in, however active. Default 12 hours. |
| Concurrent session limit | When a sign-in would exceed the limit, the oldest active sessions are revoked first. Default 5. |
The three limits belong to the workspace session policy: GET and PUT /api/v1/session-policy with body {idleTimeoutMinutes, absoluteTimeoutHours, concurrentSessionLimit} (AUTHOR on user to change). They are not edited on this screen.
Fields and options. Header text "N active session(s)". Grid columns: Device ("browser on os", with the IP address underneath), Type, IP address, Last active (newest first). Up to 200 sessions are loaded. Empty state "No active sessions."
Actions.
| Action | Effect | API |
|---|---|---|
| Log Out (row) | Revokes that session. Only your own sessions can be revoked. | DELETE /api/v1/sessions/{id} |
| Log Out All Sessions | Revokes every session of the caller, including the one in use, so the next request needs a new sign-in. Disabled when there are none. | POST /api/v1/sessions/logout-all |
| List | GET /api/v1/sessions?pageIndex=&pageSize=, rows {id, device, browser, os, ipAddress, createdAt, lastActivityAt, expiresAt} | |
| Administrator list and sign-out (API only) | Another person's sessions (AUTHOR on user) | GET /api/v1/users/{id}/sessions, POST /api/v1/users/{id}/sessions/logout-all |
A session can also be validated with GET /api/v1/auth/session (header X-Session-Token) and ended with DELETE /api/v1/auth/logout.
Errors. "Cannot revoke another user's session" (403).
Application access
Application access lets a workspace administrator decide which of the workspace's users may enter which installed application. Each application then manages its own roles on its own Roles & Permissions page. This is the middle link of the delegation chain: the platform owns the workspace, the workspace administrator grants a user access to an application, the application's administrator assigns roles inside it.
Where to find it. Security > Users & Access > Application access. Page key application-access.
Fields and options.
| Section | Content |
|---|---|
| Installed Applications | Chips Name (applicationCode) for every application with at least one installed plugin of this workspace; "No applications installed for this tenant yet." when empty. |
| Grant Access | Username (helper "Must have logged in at least once"), Application (select "(choose)"), buttons Grant and Revoke. A line "Known users: ..." lists the usernames that have a linked platform identity. |
| Current Grants | One line per grant: username, application code chip, status chip (Allowed green, Denied grey) and "granted by" followed by the actor; "No access grants yet." when empty. |
Grant records status Allowed; Revoke records status Denied. Granting again updates the existing row (one row per user and application) and the granted-by and time.
API. GET /api/v1/tenant-applications (installed applications), GET /api/v1/tenant-applications/tenant-users, GET /api/v1/tenant-applications/access, POST /api/v1/tenant-applications/access body {username, applicationCode, status} (status Allowed or Denied, default Allowed; returns 201).
bash
erp api post /api/v1/tenant-applications/access --tenant 2 --body '{"username":"priya.nair","applicationCode":"hcm","status":"Allowed"}'Permissions. The endpoints perform no capability check in this release; reach to the screen is the control.
Errors (HTTP 404).
| Message | Cause | Fix |
|---|---|---|
| "priya.nair" has no linked platform identity yet (has this user ever logged in?) | The user has never signed in, so no platform identity exists | Ask the user to sign in once, or create the account through the Users screen. |
| No tenant membership found for "priya.nair" | The identity exists but is not a member of this workspace | Check the username. |
| Unknown application "x" | The code is not in the application registry | Choose from the Application list. |
Related. Add app-owned roles and permissions, Two role tiers.
Password Policy
The Password Policy screen sets the rules every password must follow and how failed sign-ins lock an account. It has two tabs: Organization Policy (the workspace default) and Role & Department Overrides. The rules are enforced on every account creation, password change, administrator reset, temporary password and reset-link confirmation, and the lockout rules on every sign-in.
Where to find it. Security > Users & Access > Password Policy. Page key password-policy.
Key concepts.
| Term | Definition |
|---|---|
| Organization policy | One policy per workspace. When never saved, the built-in defaults below apply. |
| Override | A policy that overlays only the fields it sets, for one role, one org unit (department) or one user. |
| Effective policy | The organization policy with overrides applied in this order, each later tier overriding the earlier: department, role, user. |
| Progressive lockout | Each repeat lockout doubles the lock duration, capped at 24 hours. |
| Permanent lockout | The account stays locked until an administrator unlocks it. |
Fields and options. Organization Policy tab. Every number field has a minimum; entries below it are raised to it.
| Section | Field | Type | Default | Minimum | Description |
|---|---|---|---|---|---|
| General | Policy Name | Text | Default Policy | A label. | |
| Minimum Length | Number | 8 | 1 | ||
| Maximum Length | Number | 128 | 1 | Must not be less than Minimum Length. | |
| Character Requirements | Require Uppercase, Minimum Uppercase | Switch, number | off, 1 | 0 | The minimum applies only when the switch is on. |
| Require Lowercase, Minimum Lowercase | Switch, number | off, 1 | 0 | ||
| Require Digit, Minimum Numbers | Switch, number | off, 1 | 0 | ||
| Require Special Character, Minimum Special Characters | Switch, number | off, 1 | 0 | A special character is any character that is not a letter or digit. | |
| Restrictions | Prevent Username in Password | Switch | on | Compared with the username stripped of punctuation, case-insensitive. | |
| Prevent Email in Password | Switch | on | Compared with the part of the email before the at sign. | ||
| Prevent Employee ID in Password | Switch | off | |||
| Prevent Company Name in Password | Switch | off | The workspace brand name or name. | ||
| Prevent Common Passwords | Switch | on | Exact match against a bundled list. | ||
| Prevent Sequential Characters ("abcd", "1234") | Switch | off | Runs of 4 or more ascending or descending letters or digits. | ||
| Prevent Repeated Characters ("aaaa") | Switch | off | The same character 4 or more times in a row. | ||
| Prevent Common Dictionary Words | Switch | off | Contains a word from a bundled list. | ||
| History & Expiration | Password History (0 = disabled) | Number | 0 | 0 | The number of previous passwords that may not be reused. |
| Password Expiry Days (0 = never) | Number | 0 | 0 | At the first successful sign-in after this many days the account becomes PASSWORD_EXPIRED and sign-in is refused until the password is changed. | |
| Failed-Login Lockout | Max Failed Attempts | Number | 5 | 1 | Consecutive failures that lock the account. |
| Lockout Duration (minutes) | Number | 15 | 1 | Automatic unlock after this long. | |
| Progressive Lockout (each repeat lockout doubles the duration, up to 24h) | Switch | off | |||
| Permanent Lockout (only an administrator can unlock - no automatic timer) | Switch | off |
Save Policy saves the whole object; the notice reads "Password policy saved." (button text "Saving..." meanwhile).
Role & Department Overrides tab. The New override form:
| Field | Type or values | Default | Required | Description |
|---|---|---|---|---|
| Scope | Select: Role, Department / Org Unit, User | Role | Yes | Changing it clears the target. |
| Role / Department / User ID | Role select "(select a role)", org unit select, or a number (helper "From the Users page") | none | Yes | |
| Min Length | Number | blank | No | Blank inherits the organization value. |
| Expiry Days | Number | blank | No | Blank inherits. |
Add override is disabled until a target is chosen. Only Min Length and Expiry Days are set on this form. Every other field (complexity, restrictions, history, lockout, effective dates, priority) can be set through the API and stays blank (inherited) otherwise. Each override is shown as a card with the scope chip, target, "min length N" and "expiry Nd", an Active/Inactive switch and a delete icon whose dialog is "Delete this override?" with the text "Affected users immediately fall back to the Organization Policy (or a less specific override). There is no undo." Empty state "No overrides yet - every user follows the Organization Policy. Add one above to narrow it for a specific role, department, or user."
Override resolution. Department: among the overrides of the person's org units that are ACTIVE and within their effective dates, the highest priority wins. Role: the winning override is the one attached to the person's role with the highest role priority, ties broken by override priority and then id. User: the highest-priority active override. Overrides are applied in the order department, role, user, each overlaying only its non-blank fields.
Statuses. An override is ACTIVE (default) or INACTIVE, with optional effectiveFrom (default now) and effectiveTo.
Permissions. Saving the policy and creating, changing or deleting overrides need AUTHOR on user. Reading is open. A policy change records the event PASSWORD_POLICY_CHANGED in the account audit trail.
API and CLI.
| Method and path | Purpose |
|---|---|
GET /api/v1/password-policy | The effective organization policy |
PUT /api/v1/password-policy | Update. Omitted fields keep their current value. |
GET /api/v1/password-policy/overrides | List overrides |
POST /api/v1/password-policy/overrides | Create; body needs scopeType (ROLE, ORG_UNIT or USER) and scopeId |
PUT /api/v1/password-policy/overrides/{id} | Update (partial) |
DELETE /api/v1/password-policy/overrides/{id} | Delete |
POST /api/v1/password/validate | Dry run: body {password, username, email}, answer {valid, strength, errors}; needs no sign-in, only the tenant header |
bash
erp api put /api/v1/password-policy --tenant 2 --body '{"minLength":12,"requireDigit":true,"requireSpecial":true,"historyDepth":5,"expiryDays":90,"maxFailedAttempts":5,"lockoutDurationMinutes":15,"progressiveLockout":true}'
erp api post /api/v1/password-policy/overrides --tenant 2 --body '{"scopeType":"ROLE","scopeId":7,"minLength":14,"expiryDays":60}'
erp api post /api/v1/password/validate --tenant 2 --body '{"password":"abcd1234","username":"priya.nair"}'Limits and behaviour. The lock duration for repeat lockouts is lockoutDurationMinutes times 2 to the power of (lockouts minus 1), capped at 24 hours, when progressive lockout is on. A successful sign-in resets the counter. A password change or reset moves an account from LOCKED or PASSWORD_EXPIRED back to ACTIVE. Password hashes are never stored in clear; hashes created with an older algorithm are upgraded at the next successful sign-in. A temporary password expires after 24 hours and forces a change at the next sign-in.
Errors (HTTP 400).
| Message | Cause |
|---|---|
| Password must be at least N characters; Password must be at most N characters | Length |
| Password must contain at least N uppercase letter(s) / lowercase letter(s) / digit(s) / special character(s) | Character requirements |
| Password must not contain your username / your email address / your employee ID / your company name | Restrictions |
| This password is too common - choose something less predictable | Common password |
| Password must not contain a sequential run of characters (e.g. "abcd", "1234") | Sequential |
| Password must not contain the same character repeated 4 or more times in a row | Repeated |
| Password must not contain a common dictionary word | Dictionary |
| minLength must be at least 1; maxLength must be >= minLength; minUppercase/minLowercase/minNumbers/minSpecialChars must be >= 0; historyDepth/expiryDays must be >= 0, and maxFailedAttempts/lockoutDurationMinutes must be >= 1 | Saving the policy |
| scopeType must be one of ROLE, ORG_UNIT, USER; scopeId is required | Creating an override |
| No password policy override 9 | Unknown override id (404) |
Delegation
Delegation lets a person hand their authority to a colleague for a period, for example during leave, and see what has been handed to them. It is self-service: a delegation is always created and revoked by the person who gives it.
Where to find it. Security > Users & Access > Delegation. Page key delegations.
Key concepts.
| Term | Definition |
|---|---|
| Delegator | The caller who creates the delegation. |
| Delegate | The colleague who receives it. |
| Role scope | Blank means every role of the delegator; otherwise the one named role. The match is by the role's display name. |
| Active | Computed at read time: not revoked, and now between the start and the end. An expired delegation stops being active by itself; there is no scheduler. |
Effect. While a delegation is active the delegate is treated as holding the delegated roles: the roles appear in the delegate's role set for every permission check, and the delegate is a candidate for workflow tasks addressed to those roles and for approval limits of those roles. When it ends or is revoked the roles disappear at the next check (subject to the 60-second decision cache).
Fields and options. Panel "Delegate my authority" (tab Given by me only):
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
| Delegate to (username) | Text | empty | Yes | An existing user of the workspace. |
| Role (optional, blank = all roles) | Text | empty | No | |
| Reason | Select: Vacation, Leave, Travel, Workload, Other | Vacation | Yes | Stored as VACATION, LEAVE, TRAVEL, WORKLOAD, OTHER; OTHER when absent through the API. |
| Ends at | Date and time | empty | Yes | Delegate is disabled while empty or while the delegate is blank. |
The start time is not on the form; it is the moment of creation. The API accepts startsAt.
Tabs Given by me and Received by me. Grid columns: Delegation ("delegator -> delegate" with the reason), Roles ("all roles" or the role), Status (Active, Revoked or Expired), From, Until. Revoke appears on active rows of the Given tab only. Empty state "Nothing here yet."
Actions and API.
| Action | API |
|---|---|
| Delegate | POST /api/v1/delegations body {delegateUsername, roleScope, reason, startsAt, endsAt}, returns 201 |
| Given by me | GET /api/v1/delegations/given?pageIndex=&pageSize= |
| Received by me | GET /api/v1/delegations/received |
| Revoke | DELETE /api/v1/delegations/{id}, returns 204 |
bash
erp api post /api/v1/delegations --tenant 2 --body '{"delegateUsername":"bob","roleScope":"Leave Manager","reason":"VACATION","endsAt":"2026-10-20T18:00:00Z"}'Procedure. Cover for two weeks. Delegate to bob, Role Leave Manager, Reason Vacation, Ends at 20 October 18:00 and select Delegate. A row appears with status Active; bob sees it under Received by me.
Errors.
| Message | Cause |
|---|---|
| endsAt is required (400) | No end time |
| No user "bob" for tenant 2 (404) | Caller or delegate does not exist |
| Only the delegator who granted a delegation may revoke it (403) | Revoking someone else's delegation |
Preferences
Preferences (titled "My Preferences") holds personal settings of the signed-in person: which notification emails they receive, display options and language, formats and theme. It never shows or edits another person's settings.
Where to find it. Security > Users & Access > Preferences. Page key preferences.
Fields and options.
Notifications ("Uncheck an item to stop receiving that email"). A checked box means the email is sent.
| Checkbox label | Event type |
|---|---|
| Welcome email on account creation | WELCOME_EMAIL |
| Password changed/reset confirmation | PASSWORD_RESET |
| Account locked alert | ACCOUNT_LOCKED |
| New sign-in alert | LOGIN_ALERT |
| New device sign-in alert | NEW_DEVICE_ALERT |
| One-time sign-in codes | OTP_LOGIN |
Opting out suppresses that email from the next matching event; this is the one preference with a server-side effect. Account and security events other than these six are not covered.
Communications (shown when channels exist): a grid with one row per category (Security, Transactional, System, Workflow, Marketing, Reminder) and one column per channel. A checked cell (the default when no choice was saved) receives that category on that channel. Save Communication Preferences saves this grid on its own; the notice is "Communication preferences saved." The text warns that security messages generally should not be turned off.
Display:
| Field | Values | Default |
|---|---|---|
| Density | Comfortable, Compact | Comfortable |
| Rows per page | Number | 25 |
| Collapse sidebar by default | Checkbox | off |
Localization ("Leave a field blank to follow your organization's default"). Each select offers "Organization default" plus the entries of the localization catalog: Language, Locale, Timezone, Date format, Time format, Number format, Currency, Week start, Calendar, Measurement units. Font scale is a slider from 0.75x to 1.50x in steps of 0.05, default 1.00x. Theme (blank follows the organization), Dark mode and High contrast are checkboxes. A field the organization has locked is disabled and its label gets the suffix "(locked by admin)".
Save Preferences saves everything except the communications grid and shows "Preferences saved."
API.
| Method and path | Purpose |
|---|---|
GET, PUT /api/v1/preferences | The caller's preferences (stored as one JSON document for the caller; a blank localization field means "defer to the workspace default") |
GET /api/v1/localization/effective | Resolved values and the list of locked fields |
GET /api/v1/localization-master-data/catalog | Options for the selects |
GET, PUT /api/v1/communications/preferences | The category by channel grid |
Limits and behaviour. Rows per page, density and sidebar state are read by the client and not enforced by the server. A locked field is ignored when values are resolved, even if a value was stored earlier.
Audit Logs
The screen titled "Login History & User Audit Trail" shows two read-only trails: every sign-in attempt of the signed-in person, and every account change in the workspace. It is distinct from the Permission Audit Log and the workspace-wide Audit Log.
Where to find it. Security > Users & Access > Audit Logs. Page key user-audit-timeline.
Fields and options.
Tab Login History (your own attempts; no filters; 25 per page, server-paginated):
| Column | Content |
|---|---|
| When | Local time of the attempt |
| Result | Chip "Success", or the failure reason |
| Device | "browser on os", or "Unknown" |
| IP address | Client address, the first hop of X-Forwarded-For when present, otherwise the connection address |
Failure reasons: invalid-credentials (also unknown user and a locked account, indistinguishable by design), ip-denied, outside-allowed-hours, captcha-required, mfa-invalid-code, otp-invalid-code. An unknown or expired MFA challenge has no username and is not recorded. Empty state "No login attempts recorded yet."
Tab Account Changes:
| Field | Description |
|---|---|
| User id (optional) | Helper "Look up one user's own timeline". When filled the call asks for that user's entries. |
| Actor (optional) | Exact match on who made the change. Ignored when a user id is given. |
| Load | Loads page 1; paging then follows the grid. |
Columns: When, User (the user id), Operation (create, update, delete), Actor, What changed (field: before -> after). A password change is shown as password: "REDACTED" -> "CHANGED", or "TEMPORARY_ISSUED" for an issued temporary password; the password itself is never recorded. Empty states "No timeline loaded yet - click Load." and "No account-change records match."
This tab lists entries of entity type user: account creation, contact and profile changes, status transitions, archive, restore and delete. Password and lockout events are stored in the same table under entity type password-security and are reachable through the API; their operation names are PASSWORD_CREATED, PASSWORD_CHANGED, PASSWORD_RESET_REQUESTED, PASSWORD_RESET_COMPLETED, PASSWORD_RESET_FAILED, PASSWORD_EXPIRED, PASSWORD_POLICY_CHANGED, PASSWORD_REUSED, PASSWORD_VALIDATION_FAILED, ACCOUNT_LOCKED, ACCOUNT_UNLOCKED, ADMIN_PASSWORD_RESET and FORCED_PASSWORD_CHANGE.
API.
| Method and path | Purpose |
|---|---|
GET /api/v1/login-history?pageIndex=&pageSize= | The caller's attempts: {id, username, success, reason, device, browser, os, ipAddress, country, city, occurredAt, regionCode}. country and city are always empty. |
GET /api/v1/users/{id}/login-history | Another person's attempts (AUTHOR on user) |
GET /api/v1/user-audit?entityType=user&actor=alice&pageIndex=0&pageSize=25 | Account changes |
GET /api/v1/user-audit?entityType=password-security | Password and lockout events |
GET /api/v1/user-audit/entity?entityType=user&entityKey=14 | One user's timeline |
bash
erp api get "/api/v1/user-audit?entityType=password-security&pageSize=50" --tenant 2Limits and behaviour. Both trails are append-only and read without a capability. The Login History tab is self-service only. Rows are written from events, independently of the browser. The trails have no retention setting in this release and nothing purges them.
