---
description: Manage user identities with Aidbox User resource or delegate to external identity providers like Okta, Google, Auth0.
---

# User management

There are two ways to manage users in Aidbox:

1. Manage Users in Aidbox
2. Manage Users in external systems

## Manage Users in Aidbox

Aidbox user management is based on the [`User`](../../reference/system-resources-reference/core-module-resources.md#user) resource.\
A `User` represents an application‑level identity and is completely stored and controlled inside the Aidbox database. Each user record contains the login name, a hashed password, an active flag, and a link to FHIR user (Practitioner or Patient), and some additional fields that determine the user's effective permissions through [`AccessPolicy`](../../reference/system-resources-reference/core-module-resources.md#accesspolicy) rules.

Because everything is a resource, you can manage users the same way you manage clinical data: create [profiles](../../modules/profiling-and-validation/#what-is-profiling) to apply validation, versioned history, transactions, \_history, etc.

### Password management

Aidbox automatically hashes passwords using scrypt before storing them. You can manage them either through the dedicated `/auth/*` endpoints (self-service change and admin-initiated reset, described below) or directly via CRUD on the `User` resource.

#### Creating a user with a password

```http
PUT /User/my-user
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "my-secret-password"
}
```

The response contains the scrypt hash (format `$s0$...`) instead of the plaintext password.

#### Changing a password via CRUD

Update the `password` field via `PUT` or `PATCH`:

```http
PATCH /User/my-user
Content-Type: application/json

{
  "password": "new-secret-password"
}
```

{% hint style="warning" %}
A CRUD update does **not** require the current password. Any client with write access to the `User` resource can change any user's password. Protect the `User` resource with an [AccessPolicy](../authorization/access-policies.md) that restricts write access. For an end-user flow that does verify the current password, use [`/auth/change-password`](#self-service-password-change) instead.
{% endhint %}

When audit logging is enabled, password changes generate an AuditEvent with DICOM subtype `110139` ("User password changed"). Resets through the reset-link flow also carry the `password-self-reset` subtype, and admin-issued resets carry `password-force-reset`. See [Audit and Logging](../audit-and-logging.md) for details.

#### Self-service password change

Signed-in users can change their own password by providing the current one. Unlike a direct CRUD update, this verifies the current password before applying the change.

```http
POST /auth/change-password
Content-Type: application/json

{
  "currentPassword": "old-password",
  "newPassword":     "new-password"
}
```

On success, Aidbox updates the password and signs the user out of every active session — they have to log in again everywhere. If the current password is wrong, the new one is the same as the current one, or it violates the [policy](#password-policy), the request fails and the password is not changed.

#### Admin-initiated password reset

When a user forgot their password or their account was compromised, an administrator can issue a one-time reset link. Aidbox immediately invalidates the user's current password, signs them out of every device, and prepares a fresh link that can be used once. The response contains the URL to share with the user.

{% hint style="info" %}
Force reset does not disable two-factor authentication. If the user lost their TOTP device, reset or disable 2FA for that user separately — otherwise the reset link will still ask for a TOTP code before letting them set a new password.
{% endhint %}

```http
POST /auth/force-reset-password
Content-Type: application/json

{
  "userId": "user-1"
}
```

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "code": "password_reset_link_issued",
  "data": {
    "resetUrl": "https://<aidbox>/auth/reset-password?token=eyJhbGc...",
    "token":    "eyJhbGc..."
  }
}
```

The link is valid for **15 minutes** and lets the user set a new password once. Issuing another reset for the same user replaces the previous link.

{% hint style="warning" %}
`/auth/force-reset-password` has no default AccessPolicy — grant it explicitly to administrators only.
{% endhint %}

{% hint style="info" %}
Aidbox does not deliver the reset link itself. Pass `resetUrl` to the user out-of-band — email, SMS, in-app message, or whatever channel you trust.
{% endhint %}

#### Resetting a password via reset link

When the user opens the reset link, Aidbox renders an HTML page that walks them through setting a new password. There are three possible outcomes:

* The token is missing, expired or already used — the user sees an error page with a Back to login action.
* The user has two-factor authentication enabled — they are asked for a TOTP code first, then for a new password.
* No 2FA — they are asked directly for a new password.

Once the new password is saved, Aidbox signs the user out everywhere and the link stops working.

Add an optional `redirect_to` to the reset link to override where the page sends the user after a successful reset (default `/auth/login`):

```http
GET /auth/reset-password?token=<reset-token>&redirect_to=L3Vp
```

Base64-encoded path, preserved across the 2FA step. The decoded value must start with `/`, otherwise Aidbox falls back to `/auth/login`.

If you build your own UI instead of relying on the built-in page, the JSON endpoints behind that flow look like this.

For users without 2FA, the new password is submitted directly:

```http
POST /auth/reset-password
Content-Type: application/json

{
  "token":       "<reset-token>",
  "newPassword": "new-password"
}
```

For users with [two-factor authentication](../authentication/two-factor-authentication.md), the user first confirms a TOTP code:

```http
POST /auth/reset-password-mfa
Content-Type: application/json

{
  "token": "<reset-token>",
  "totp":  "123456"
}
```

In response Aidbox returns a short-lived password-set token (valid for one minute) that the UI then submits together with the new password:

```http
POST /auth/reset-password
Content-Type: application/json

{
  "token":       "<passwordSetToken>",
  "newPassword": "new-password"
}
```

#### Password policy

Aidbox can enforce a single optional password rule:

| Setting                                | Env var                                   | Description                                            |
|----------------------------------------|-------------------------------------------|--------------------------------------------------------|
| `security.user-password.min-length`    | `BOX_SECURITY_USER_PASSWORD_MIN_LENGTH`   | Minimum user password length (positive integer).       |

If the setting is not configured, Aidbox does not enforce a minimum password length. When set, the policy applies whenever someone tries to set a plaintext password — through `/auth/change-password`, `/auth/reset-password`, or a direct write to a `User` resource. Passwords that are already stored as a scrypt hash (for example when copying a `User` record between environments) are not re-checked.

{% hint style="info" %}
Aidbox intentionally does not enforce password complexity, expiry, or reuse rules. This follows [NIST SP 800-63B](https://pages.nist.gov/800-63-3/sp800-63b.html), which recommends against periodic forced password changes and composition rules.
{% endhint %}

### Security considerations

{% hint style="warning" %}
**Password hash exposure**: `GET /User/:id` and `GET /User?` return the scrypt password hash in the response body. Only the `/auth/userinfo` endpoint strips the password field. Use an AccessPolicy to restrict read access to the `User` resource for non-admin clients.
{% endhint %}

{% hint style="info" %}
**No automatic account lockout**: Aidbox does not lock accounts after repeated failed login attempts. The only lockout mechanism is manually setting `User.inactive` to `true`. See [Prohibit user to login](../../tutorials/security-access-control-tutorials/prohibit-user-to-login.md).
{% endhint %}

See also:

* [User resource reference](../../reference/system-resources-reference/core-module-resources.md#user)
* [Creating user tutorial](../../tutorials/security-access-control-tutorials/creating-user-and-set-up-full-user-access.md)
* [How to prohibit user to login](../../tutorials/security-access-control-tutorials/prohibit-user-to-login.md)

## Manage Users in external systems

If you already have an identity provider, you can delegate authentication to it and keep all identities outside Aidbox. Aidbox becomes a Service Provider that trusts the external IdP and focuses on authorization.

Two building blocks are involved:

* `IdentityProvider` – resource to configure an external identity provider. Log in to Aidbox UI with SSO. When users hit the Aidbox UI, they are redirected to the IdP; after successful login, the IdP posts an ID‑token back to Aidbox, establishing a browser session. Aidbox retrieves user data from external identity provider and stores it in the User resource.
* `TokenIntrospector` – For API access, point your application to the IdP directly, then present the resulting JWT/Opaque token to Aidbox. The TokenIntrospector resource tells Aidbox how to verify the token signature.

See also:

{% content-ref url="../authentication/sso-with-external-identity-provider.md" %}
[sso-with-external-identity-provider.md](../authentication/sso-with-external-identity-provider.md)
{% endcontent-ref %}

{% content-ref url="../authentication/token-introspector.md" %}
[token-introspector.md](../authentication/token-introspector.md)
{% endcontent-ref %}

### Automatically create users from external systems
In some cases, you want to authenticate with an external IdP and still have a corresponding User resource inside Aidbox for auditing, patient‑to‑user mapping, or granular AccessPolicy rules. Aidbox supports just‑in‑time user provisioning:
- In case of SSO, Users are created automatically.
- In case of API access, it is possible to create User at first request using [setting](../../reference/all-settings.md#security.introspection-create-user).

See also:

{% content-ref url="../../tutorials/security-access-control-tutorials/keycloak-auto-create-user.md" %}
[keycloak-auto-create-user.md](../../tutorials/security-access-control-tutorials/keycloak-auto-create-user.md)
{% endcontent-ref %}
