Users API
The Users API provides full lifecycle management for user accounts within a tenant: creating, reading, updating, disabling, and deleting users; assigning roles; importing and exporting users in bulk; and managing phone numbers and two-factor authentication settings for individual accounts.
All endpoints in this section require the x-tenant header and, unless noted otherwise, require the manage:users permission.
User Management
/api/usersRequires: manage:usersList all users in the tenant. Supports pagination and filtering by role, account status, and search query. Returns user objects with summary information (does not include 2FA status or session details — use the individual user endpoint for those).
Query parameters
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
limit | integer | Items per page (default: 20, max: 100) |
search | string | Full-text search across email, username, firstName, lastName |
role | string | Filter by role name |
status | active | disabled | locked | Filter by account status |
Success response
{
"ok": true,
"data": {
"data": [
{
"id": "usr_abc123",
"email": "[email protected]",
"username": "alice",
"firstName": "Alice",
"lastName": "Smith",
"enabled": true,
"emailVerified": true,
"createdAt": "2025-01-15T10:30:00Z",
"roles": ["editor", "viewer"]
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 87,
"totalPages": 5
}
}
}/api/usersRequires: manage:usersCreate a new user account in the tenant. The user is created in both the Auris database and the
underlying Keycloak realm. If password is omitted, the account is created without a password
(the user must set one via a magic link or password reset flow).
Request body
{
"email": "[email protected]",
"username": "bob",
"firstName": "Bob",
"lastName": "Jones",
"password": "initialPassword123",
"roles": ["viewer"],
"enabled": true
}All fields except email are optional.
Success response
{
"ok": true,
"data": {
"id": "usr_def456",
"email": "[email protected]",
"username": "bob",
"firstName": "Bob",
"lastName": "Jones",
"enabled": true,
"emailVerified": false,
"createdAt": "2025-02-18T09:00:00Z",
"roles": ["viewer"]
}
}Error codes
| Code | HTTP | Description |
|---|---|---|
EMAIL_TAKEN | 409 | A user with this email already exists in the tenant |
USERNAME_TAKEN | 409 | Username is already in use |
VALIDATION_ERROR | 400 | Request body failed schema validation |
/api/users/[id]Requires: manage:usersRetrieve a single user by their ID. Returns full user details including role memberships, 2FA status, phone number, group memberships, and last login information.
Success response
{
"ok": true,
"data": {
"id": "usr_abc123",
"email": "[email protected]",
"username": "alice",
"firstName": "Alice",
"lastName": "Smith",
"enabled": true,
"emailVerified": true,
"phoneNumber": "+39 02 1234567",
"phoneNumberVerified": true,
"createdAt": "2025-01-15T10:30:00Z",
"lastLoginAt": "2025-02-17T14:22:00Z",
"roles": ["editor", "viewer"],
"twoFactor": {
"totpEnabled": true,
"smsEnabled": false,
"webauthnEnabled": false
}
}
}Error codes
| Code | HTTP | Description |
|---|---|---|
NOT_FOUND | 404 | User does not exist in this tenant |
/api/users/[id]Requires: manage:usersUpdate a user’s profile fields. All fields are optional — only provided fields are updated.
To disable a user without deleting them, set enabled: false.
Request body
{
"firstName": "Alicia",
"lastName": "Smith-Jones",
"enabled": false
}Success response
{
"ok": true,
"data": {
"id": "usr_abc123",
"email": "[email protected]",
"firstName": "Alicia",
"lastName": "Smith-Jones",
"enabled": false
}
}/api/users/[id]Requires: manage:usersSoft-delete a user. The user’s account is disabled and marked as deleted in the Auris database, and their Keycloak account is removed. Active sessions are invalidated immediately.
Soft-deletion is irreversible through the API. The user record is retained in the database for audit log consistency but cannot be recovered or logged into. Use enabled: false via PUT /api/users/[id] if you want to temporarily disable without deletion.
Success response
{
"ok": true,
"data": { "deleted": true }
}Role Assignment
/api/users/[id]/rolesRequires: manage:usersList all roles currently assigned to a user.
Success response
{
"ok": true,
"data": [
{
"id": "role_123",
"name": "editor",
"description": "Can create and edit content",
"color": "#3b82f6"
}
]
}/api/users/[id]/rolesRequires: manage:usersAssign a role to a user. The role must exist in the tenant. Assigning the same role twice is a no-op (idempotent).
Request body
{
"roleId": "role_123"
}Success response
{
"ok": true,
"data": { "assigned": true }
}Error codes
| Code | HTTP | Description |
|---|---|---|
NOT_FOUND | 404 | Role does not exist in this tenant |
SELF_ROLE_CHANGE | 403 | Cannot modify your own roles |
/api/users/[id]/rolesRequires: manage:usersRemove a role from a user. Removing a role the user does not have is a no-op (idempotent).
Request body
{
"roleId": "role_123"
}Success response
{
"ok": true,
"data": { "removed": true }
}Bulk Import
/api/users/importRequires: admin:allImport users in bulk from a CSV or JSON file. The import runs asynchronously — the endpoint
returns a job ID immediately. Poll GET /api/users/import/[id] to track progress.
Request format: multipart/form-data
| Field | Type | Description |
|---|---|---|
file | binary | CSV or JSON file |
format | csv | json | File format |
sendWelcomeEmail | boolean | Send welcome email to new users (default: false) |
CSV format (first row is header):
email,firstName,lastName,username,password,roles
[email protected],Alice,Smith,alice,,viewer
[email protected],Bob,Jones,bob,TempPass123,editorJSON format:
[
{
"email": "[email protected]",
"firstName": "Alice",
"lastName": "Smith",
"roles": ["viewer"]
}
]Success response (job created)
{
"ok": true,
"data": {
"jobId": "import_xyz789",
"status": "pending",
"totalRows": 142,
"createdAt": "2025-02-18T10:00:00Z"
}
}/api/users/importRequires: admin:allList all import jobs for the current tenant, ordered by creation time descending.
Success response
{
"ok": true,
"data": {
"data": [
{
"id": "import_xyz789",
"fileName": "users-2025-02.csv",
"format": "csv",
"status": "completed",
"totalRows": 142,
"processedRows": 142,
"successCount": 140,
"errorCount": 2,
"createdAt": "2025-02-18T10:00:00Z",
"completedAt": "2025-02-18T10:01:34Z"
}
],
"pagination": { "page": 1, "limit": 20, "total": 5, "totalPages": 1 }
}
}/api/users/import/[id]Requires: admin:allGet the current status and error details of an import job.
Success response
{
"ok": true,
"data": {
"id": "import_xyz789",
"status": "completed",
"totalRows": 142,
"processedRows": 142,
"successCount": 140,
"errorCount": 2,
"errors": [
{
"row": 45,
"email": "bad@",
"error": "Invalid email address"
},
{
"row": 98,
"email": "[email protected]",
"error": "Email already exists"
}
]
}
}Import job statuses: pending, processing, completed, failed, partial.
Bulk Export
/api/users/exportRequires: admin:allTrigger a user export. The export runs asynchronously. Poll GET /api/users/export to find the
job, then download using GET /api/users/export/[id]/download once status is completed.
Request body
{
"format": "csv"
}format is "csv" or "json".
Success response
{
"ok": true,
"data": {
"id": "export_abc123",
"status": "pending",
"format": "csv",
"createdAt": "2025-02-18T11:00:00Z"
}
}/api/users/exportRequires: admin:allList all export jobs.
/api/users/export/[id]/downloadRequires: admin:allDownload the export file once the job status is completed. Returns the raw file binary with
an appropriate Content-Disposition header.
Export files are stored temporarily and expire after 24 hours. Download them promptly after the job completes.
Phone Number Management
These endpoints allow authenticated users to manage their own phone number. No special permission beyond a valid access token is required.
/api/user/phone/setRequires: authenticated userSet or update the authenticated user’s phone number. After setting, the number must be verified
using POST /api/user/phone/verify. An SMS OTP is sent to the provided number.
Request body
{
"phoneNumber": "+39021234567"
}The phone number must be in E.164 format (international format with country code).
Success response
{
"ok": true,
"data": {
"sent": true,
"phoneNumber": "+39021234567"
}
}Error codes
| Code | HTTP | Description |
|---|---|---|
INVALID_PHONE | 400 | Number is not in E.164 format |
PHONE_TAKEN | 409 | Number is already associated with another account |
SMS_RATE_LIMITED | 429 | Too many SMS requests (max 5 per hour) |
/api/user/phone/verifyRequires: authenticated userVerify the phone number with the OTP code sent via SMS. On success, phoneNumberVerified is set
to true on the user account.
Request body
{
"code": "482910"
}Success response
{
"ok": true,
"data": { "verified": true }
}Error codes
| Code | HTTP | Description |
|---|---|---|
INVALID_OTP | 400 | Code is incorrect |
OTP_EXPIRED | 400 | Code has expired (TTL: 10 minutes) |
MAX_ATTEMPTS | 400 | Maximum verification attempts exceeded |
Two-Factor Authentication
/api/user/2fa/sms/enableRequires: authenticated userEnable SMS OTP as a 2FA method for the authenticated user. Requires a verified phone number. An OTP is sent to confirm the phone can receive codes before enabling.
Request body
{
"code": "123456"
}Provide the OTP that was sent to the user’s verified phone number.
Success response
{
"ok": true,
"data": { "smsEnabled": true }
}Error codes
| Code | HTTP | Description |
|---|---|---|
PHONE_NOT_VERIFIED | 400 | User does not have a verified phone number |
INVALID_OTP | 400 | Confirmation code is incorrect |
/api/user/2fa/webauthn/enableRequires: authenticated userBegin the WebAuthn passkey registration ceremony to enable WebAuthn as a 2FA method. Returns
a registration challenge. The client must complete the ceremony using the browser’s WebAuthn API
and submit the AuthenticatorAttestationResponse to POST /api/user/2fa/webauthn/challenge.
Request: No body required.
Success response (registration options)
{
"ok": true,
"data": {
"challenge": "base64url-challenge",
"rp": { "name": "Auris", "id": "your-auris-domain.com" },
"user": {
"id": "base64url-user-id",
"name": "[email protected]",
"displayName": "Alice Smith"
},
"pubKeyCredParams": [{ "type": "public-key", "alg": -7 }],
"timeout": 60000,
"attestation": "none"
}
}Use the @simplewebauthn/browser library to handle this challenge in the browser.
Related
- Managing Users — Guide to user lifecycle management
- Import & Export — Bulk user migration via CSV/JSON
- SCIM 2.0 Provisioning — Automated user provisioning
- Users & Roles — Manage users from the Console
- User Import & Export API — Bulk import and export endpoints