Skip to content
This repository was archived by the owner on Mar 17, 2026. It is now read-only.

Commit 5eb9625

Browse files
committed
Big bunch of documentation fixes
1 parent fe76e55 commit 5eb9625

File tree

13 files changed

+279
-21
lines changed

13 files changed

+279
-21
lines changed

docs/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@
254254
* [Patient data access API](access-control/authorization/scoped-api/patient-data-access-api.md)
255255
* [Label-based Access Control](access-control/authorization/label-based-access-control.md)
256256
* [Audit and Logging](access-control/audit-and-logging.md)
257+
* [Security Hardening](access-control/security-hardening.md)
257258

258259
## Artifact Registry
259260

docs/access-control/authorization/label-based-access-control.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ securityLabel:
4747
code: M
4848
```
4949
50+
{% hint style="warning" %}
51+
**User.securityLabel and Bearer tokens**: Labels from `User.securityLabel` are applied only when the user is identified via **cookie-based session** (e.g. form login in the Aidbox UI). When the request uses a **Bearer token** (e.g. from Resource Owner Password Credentials or an opaque token), Aidbox does not look up the User's `securityLabel`; those sessions do not carry user labels. For API access with LBAC, use **JWT tokens** that include security labels in the `scope` claim (format `system|code`), as described in the **scope claim in JWT** section above.
52+
{% endhint %}
53+
5054
### Expanding confidentiality security label
5155

5256
The security label for confidentiality is [hierarchical](https://terminology.hl7.org/ValueSet-v3-Confidentiality.html). The code may contain several others.
@@ -173,9 +177,13 @@ subject:
173177
To prevent security labels from appearing in the outcome, set the `strip labels` env:
174178

175179
```yaml
176-
BOX_FEATURES_SECURITY__LABELS_STRIP__LABELS=true
180+
BOX_SECURITY_LBAC_STRIP_LABELS=true
177181
```
178182

183+
{% hint style="info" %}
184+
The legacy name `BOX_FEATURES_SECURITY__LABELS_STRIP__LABELS` is deprecated but still supported. See [all-settings](../../../reference/all-settings.md#security.lbac.strip-labels).
185+
{% endhint %}
186+
179187
**Stripping examples**
180188

181189
The security labels from `meta.security` and `_status` fields have been removed from the outcome.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
description: CORS, security headers, cookies, session management, and infrastructure security for Aidbox.
3+
---
4+
5+
# Security Hardening
6+
7+
This page describes infrastructure-level security features in Aidbox: CORS, security headers, cookie flags, session management, and what is not implemented. Use it together with [Access Policies](authorization/access-policies.md), [Audit and Logging](audit-and-logging.md), and [User management](identity-management/user-management.md) for a complete security picture.
8+
9+
## CORS
10+
11+
Cross-Origin Resource Sharing (CORS) is **enabled by default**. Aidbox supports:
12+
13+
* **Wildcard mode**`BOX_SECURITY_CORS_ORIGINS=*` (default). Any `Origin` header is echoed back in `Access-Control-Allow-Origin`. Use only in development or when all origins are trusted.
14+
* **Whitelist mode** — Set `BOX_SECURITY_CORS_ORIGINS` to a comma-separated list of origins, e.g. `https://app.example.com,https://trusted.example.com`. Only those origins receive CORS headers; requests from other origins get no `Access-Control-*` headers (but the API still responds).
15+
* **Disabled** — Set `BOX_SECURITY_CORS_ENABLED=false` to disable CORS entirely.
16+
17+
Preflight `OPTIONS` requests are handled: allowed methods and requested headers are reflected in `Access-Control-Allow-Methods` and `Access-Control-Allow-Headers`. Credentials are supported (`Access-Control-Allow-Credentials: true`). Settings can be changed at runtime via the [Settings API](../reference/all-settings.md) (or environment variables).
18+
19+
See [security.cors.enabled](../reference/all-settings.md#security.cors.enabled) and [security.cors.origins](../reference/all-settings.md#security.cors.origins).
20+
21+
## Cookie security
22+
23+
Session cookies set by Aidbox (e.g. after login) use:
24+
25+
* **HttpOnly** — set, to reduce XSS-based cookie theft
26+
* **SameSite=Lax** — set, to reduce CSRF from cross-site requests
27+
28+
The **Secure** flag is not set by Aidbox. When Aidbox is behind HTTPS (e.g. reverse proxy), consider configuring the proxy or application to set `Secure` on cookies if your deployment supports it.
29+
30+
## Session and token management
31+
32+
* **Session expiration** — Default session (cookie) lifetime is configurable (e.g. via AuthConfig). Expired sessions are cleaned up automatically.
33+
* **Access token expiration** — Configurable per [Client](identity-management/application-client-management.md) (e.g. `auth.client_credentials.access_token_expiration`). Tokens are rejected after expiry (401).
34+
* **Sessions list** — Active sessions can be inspected via the `Session` resource (if available in your setup).
35+
36+
See [OAuth 2.0](authentication/oauth-2-0.md) and [Client management](identity-management/application-client-management.md).
37+
38+
## What is not implemented
39+
40+
The following are **not** implemented in Aidbox. Rely on operational measures or reverse proxy where needed:
41+
42+
| Feature | Description |
43+
|--------|-------------|
44+
| **Rate limiting** | No request throttling on API or auth endpoints. Use a reverse proxy or WAF for rate limiting. |
45+
| **Brute-force protection** | No automatic account lockout after failed login attempts. Use the [User.inactive](../tutorials/security-access-control-tutorials/prohibit-user-to-login.md) flag to lock accounts manually, or implement throttling at the proxy. |
46+
| **HSTS** | Header not set. Add at reverse proxy when using HTTPS. |
47+
| **X-Content-Type-Options / Referrer-Policy** | Not set. Add at reverse proxy for defense in depth. |
48+
49+
## Infrastructure recommendations
50+
51+
* **TLS** — Terminate TLS at a reverse proxy or load balancer. Do not expose Aidbox directly to the internet without encryption.
52+
* **Reverse proxy** — Use nginx, Traefik, or similar to add security headers (HSTS, X-Content-Type-Options, Referrer-Policy), rate limiting, and DDoS mitigation.
53+
* **Network** — Restrict access to Aidbox and the database to trusted networks where possible.
54+
55+
## See also
56+
57+
* [All settings (CORS, CSP)](../reference/all-settings.md)`security.cors.*`, `security.content-security-policy-header`
58+
* [Audit and Logging](audit-and-logging.md)
59+
* [User management](identity-management/user-management.md) — password and lockout
60+
* [Prohibit user to login](../tutorials/security-access-control-tutorials/prohibit-user-to-login.md) — manual lockout via `User.inactive`

docs/api/bulk-api/dump-sql.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ description: Export SQL query results as CSV or ndjson stream using $dump-sql op
66

77
## Dump results of the sql query
88

9-
`$dump-sql` operation takes the sql query and responds with the Chunked Encoded stream in CSV format or in NDJSON format. Useful to export data for analytics.
9+
`$dump-sql` operation takes the sql query and responds with the Chunked Encoded stream in TSV format (default) or in JSON/NDJSON format. Useful to export data for analytics.
10+
11+
{% hint style="warning" %}
12+
**Streaming and errors**: The response is streamed. If the SQL is invalid or the request body is missing or malformed, the server may still return **HTTP 200** and write error text into the response body instead of returning 4xx with an OperationOutcome. Check the response body for error messages when the output is unexpected.
13+
{% endhint %}
1014

1115
```typescript
1216
POST [base]/$dump-sql

docs/api/bulk-api/export.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Export operations run one at a time to prevent resource exhaustion. If you attem
1212

1313
## Cloud storage setup
1414

15+
$export requires cloud storage to be configured. If no storage provider is set, export requests (system-, group-, or patient-level) return **500** with an error such as "storage-type not specified". Storage validation is performed before other checks (e.g. group existence or output format).
16+
1517
Aidbox exports data to cloud storage backends including GCP, Azure, and AWS. Export files are organized in timestamped folders with the pattern `<datetime>_<uuid>` to ensure unique paths for each export operation.
1618

1719
Each cloud provider supports two authentication modes: credential-based (using stored keys or tokens) and workload identity (using cloud-native pod identity). Workload identity is recommended for managed Kubernetes deployments (GKE, AKS) as it eliminates the need to manage credentials in Aidbox resources and uses the pod's identity to authenticate with cloud storage.

docs/api/bulk-api/purge.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ This operation implements the [FHIR Patient Purge](https://build.fhir.org/patien
1616
**Idempotent**: Purging a non-existent patient returns 200 (sync) or 202 (async) without error. This allows re-running `$purge` after a partial failure.
1717
{% endhint %}
1818

19+
{% hint style="info" %}
20+
**After purge**: Purged resources are permanently removed. Requests to read them return **404 Not Found** (not 410 Gone), since the resources no longer exist.
21+
{% endhint %}
22+
1923
{% hint style="warning" %}
2024
**Scoped references**: Only resources that reference the patient with the full reference format (e.g., `Patient/<id>`) are deleted. Resources referencing a different resource type with the same ID are not affected.
2125
{% endhint %}
@@ -32,7 +36,9 @@ POST /fhir/Patient/<patient-id>/$purge
3236

3337
## Parameters
3438

35-
The request body is optional. When provided, it must be a `Parameters` resource with the following optional parameter:
39+
The request body is optional. When provided, it must be a FHIR `Parameters` resource (e.g. `{"resourceType": "Parameters"}`). An empty JSON body `{}` is rejected with **422** and "Request body must be a Parameters resource". Omit the body or send `{"resourceType": "Parameters"}` when no custom parameters are needed.
40+
41+
Optional parameter:
3642

3743
| Parameter | Type | Description |
3844
| ------------------------ | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

docs/api/rest-api/fhir-search/README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ List of supported modifiers:
154154
| :not | token | Negates the search value | `gender:not=male` |
155155
| :of-type | token | Search for resource identifier | `identifier:of-type=system` |
156156
| :i | token | Case-insensitive search | `email:[email protected]` |
157-
| :below | uri | Tests whether the value in a resource is or is subsumed by the supplied parameter value (is-a, or hierarchical relationships) | `url:below=http://acme.org/fhir/` |
157+
| :below | uri | Not supported for **url** parameter (ValueSet, CodeSystem, etc.) — returns 500. See [uri](searchparameter.md#uri). | `_source:below=` supported; `url:below=` returns 500 |
158158
| :not | uri, reference, token | Negates the search value | `url:not=http://acme.org/fhir/` |
159159
| :identifier | reference | Search by identifier of referenced resource | `subject:identifier=urn:oid:1.2.3.4` |
160160
| :btw | date | Search for dates between two values. Defined by Aidbox, not FHIR. | `birthdate:btw=1980,1981` |
@@ -201,6 +201,14 @@ See also:
201201
[chaining.md](chaining.md)
202202
{% endcontent-ref %}
203203

204+
## Known limitations
205+
206+
| Feature | Limitation |
207+
|--------|-------------|
208+
| **Quantity search with unit** | Specifying a unit in the value (e.g. `value-quantity=75.5\|\|kg`) is not implemented; returns 400. Only numeric value comparison is supported. See [quantity](searchparameter.md#quantity). |
209+
| **url :below modifier** | The `:below` modifier for the **url** search parameter (ValueSet, CodeSystem, StructureDefinition) is not supported; returns 500. `_source:below` works. See [uri](searchparameter.md#uri). |
210+
| **Component-level composite** | `component-code-value-quantity` (and similar component composites) may not return results; top-level composite search works. See [composite](searchparameter.md#composite). |
211+
204212
## Other ways to search
205213

206214
Sometimes FHIR Search API is not enough. For example, there's no way to search using a case-insensitive match without starts-with **string** type logic (combining token and string types), which is useful to search, say, for domains of emails.&#x20;

docs/api/rest-api/fhir-search/searchparameter.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ Token searches support these modifiers:
125125
| :in | Search within a ValueSet | `code:in=/ValueSet/test-codes` |
126126
| :i | Case-insensitive search | `code:i=TEST123` |
127127
| :not | Negates the search value | `code:not=inactive` |
128-
| :of-type | Search for resource identifier | \`identifier:of-type=system |
128+
| :of-type | Search for resource identifier | `identifier:of-type=system` |
129129

130130
### uri
131131

@@ -143,9 +143,12 @@ URI searches support these modifiers:
143143
| Modifier | Description | Example |
144144
| -------- | ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
145145
| :missing | Matches resources that do not have a value in the field | `url:missing=true` |
146-
| :below | Tests whether the value in a resource is or is subsumed by the supplied parameter value (is-a, or hierarchical relationships) | `url:below=http://acme.org/fhir/` |
147146
| :not | Negates the search value | `url:not=http://example.com` |
148147

148+
{% hint style="warning" %}
149+
The **:below** modifier is not supported for the **url** search parameter (e.g. on ValueSet, CodeSystem, StructureDefinition). Queries such as `ValueSet?url:below=http://hl7.org` return 500 with "Unsupported search parameter 'url:below'". Other URI-type parameters (e.g. `_source`) may accept `:below`.
150+
{% endhint %}
151+
149152
### reference
150153

151154
Reference search parameters match against references to other resources. They are used to search for resources that reference a specific resource.
@@ -240,8 +243,8 @@ Quantity search parameters match against values with units. They support the sam
240243
| ne | Not equal | `weight=ne100` |
241244
| gt | Greater than | `weight=gt100` |
242245

243-
However, Aidbox supports only numbers, not system with code.\
244-
For example, `weight=100` will match resources with `weight` exactly equal to "100", the unit is ignored.
246+
However, Aidbox supports only numeric value comparison; unit specification is not implemented.\
247+
For example, `value-quantity=75.5` matches by value only. Using a unit in the search value (e.g. `value-quantity=75.5\|\|kg`) returns **400** with the message "quantity with unit specified is not implemented".
245248

246249
### composite
247250

@@ -281,6 +284,10 @@ GET /fhir/Observation?code=loinc|12907-1&value-quantity=1 // found
281284
GET /fhir/Observation?code=loinc|12907-1&value-quantity=2 // found
282285
```
283286

287+
{% hint style="info" %}
288+
**Component-level composite**: Top-level composite search (e.g. `code-value-quantity`) works as described. The `component-code-value-quantity` parameter (matching on Observation.component) may not return results for component-level matching; this is a known limitation.
289+
{% endhint %}
290+
284291
### special
285292

286293
Special search parameters have unique search behavior that cannot be expressed using the standard search parameter types. The behavior of special search parameters must be explicitly defined in their SearchParameter definition. Special parameters are useful for cases where the standard parameter types (string, token, reference, etc.) cannot adequately express the desired search functionality.

0 commit comments

Comments
 (0)