Binary Storage
Fire Arrow Server integrates with Azure Blob Storage to store binary files (images, documents, PDFs, etc.) alongside your FHIR resources. Binary data is referenced in FHIR resources using firearrow:// URLs, which the server automatically resolves to time-limited, pre-signed Azure Blob URLs when clients read the resources.
How It Works
- Upload a file via
$binary-upload, receiving afirearrow://URL - Store the URL in any FHIR resource field (e.g.,
Patient.photo.url,DocumentReference.content.attachment.url) - Read the resource - Fire Arrow automatically replaces
firearrow://URLs with time-limited pre-signed Azure Blob URLs
Uploading Files
Multipart Upload
The most common approach for uploading files from client applications:
curl -X POST http://localhost:8080/fhir/\$binary-upload \
-H "Authorization: Bearer <your-token>" \
-F "resourceReference=Patient/123" \
-F "[email protected]"
resourceReference- the FHIR resource this binary belongs to (used for authorization)file- the binary file to upload
JSON Upload (Base64)
For programmatic uploads or when multipart isn't convenient:
curl -X POST http://localhost:8080/fhir/\$binary-upload \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"resourceReference": "Patient/123",
"data": "iVBORw0KGgoAAAANSUhEUg...",
"contentType": "image/jpeg"
}'
Upload Response
Both upload methods return a FHIR Parameters resource:
{
"resourceType": "Parameters",
"parameter": [
{ "name": "url", "valueUrl": "firearrow://my-container/a1b2c3d4-photo.jpg" },
{ "name": "contentType", "valueString": "image/jpeg" },
{ "name": "size", "valueInteger": 204800 }
]
}
Use the url value in your FHIR resources:
curl -X PUT http://localhost:8080/fhir/Patient/123 \
-H "Content-Type: application/fhir+json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"resourceType": "Patient",
"id": "123",
"name": [{ "family": "Smith", "given": ["Jane"] }],
"photo": [{
"contentType": "image/jpeg",
"url": "firearrow://my-container/a1b2c3d4-photo.jpg"
}]
}'
Reading Resources with Binary URLs
When you read a resource containing firearrow:// URLs, Fire Arrow Server automatically replaces them with time-limited, pre-signed Azure Blob Storage URLs:
curl http://localhost:8080/fhir/Patient/123 \
-H "Authorization: Bearer <your-token>"
Response (note the resolved URL):
{
"resourceType": "Patient",
"id": "123",
"name": [{ "family": "Smith", "given": ["Jane"] }],
"photo": [{
"contentType": "image/jpeg",
"url": "https://myaccount.blob.core.windows.net/my-container/a1b2c3d4-photo.jpg?sv=2021-06-08&se=2026-01-15T10%3A02%3A00Z&sig=..."
}]
}
The pre-signed URL is valid for a limited time (default: 120 seconds). After expiration, clients need to re-read the resource to get a fresh URL.
Pre-signed URLs are generated on every read, so clients should fetch the resource just before they need to access the binary content rather than caching the URL long-term.
Authorization
Binary upload is governed by a single binary-upload authorization rule per client role. The validator named on the rule supplies the per-resource scope, so the same rule both permits the $binary-upload operation and decides whether the caller may attach a binary to the resource named in resourceReference. A separate update rule is not required for upload authorisation.
Example rules:
fire-arrow:
authorization:
validation-rules:
- client-role: "Patient"
resource: "Binary"
operation: "binary-upload"
validator: "PatientCompartment"
- client-role: "Practitioner"
resource: "Binary"
operation: "binary-upload"
validator: "LegitimateInterest"
Up to and including Fire Arrow Server 1.9.1, the resource-scope check for $binary-upload was not consistently applied — the binary-upload rule alone effectively decided access regardless of which resource was named in resourceReference. The validator on the binary-upload rule now governs both the operation permission and the per-resource scope. Re-check your binary-upload rules' validators to confirm they reflect the access you actually intend each client role to have.
See the Media and Binary Storage how-to for a complete end-to-end example with authorization rules, uploads, and file management. For the full $binary-upload operation reference, see Custom Operations.
Configuration
Configure binary storage under the fire-arrow.binary-storage key in your application.yaml:
fire-arrow:
binary-storage:
enabled: true
azure:
connection-string: "${AZURE_STORAGE_CONNECTION_STRING}"
container-name: "fhir-binaries"
max-file-size: 10485760 # 10 MB
pre-signed-url-expiration-seconds: 120
| Property | Description | Default |
|---|---|---|
enabled | Enable binary storage | false |
azure.connection-string | Azure Blob Storage connection string | -- |
azure.container-name | Blob container name | -- |
azure.max-file-size | Maximum upload size in bytes | 10485760 (10 MB) |
azure.pre-signed-url-expiration-seconds | How long pre-signed URLs remain valid | 120 |
Using Managed Identity
For production deployments on Azure, you can use managed identity instead of connection strings. Replace the connection-string with your storage account's endpoint:
fire-arrow:
binary-storage:
enabled: true
azure:
endpoint: "https://myaccount.blob.core.windows.net"
container-name: "fhir-binaries"
When endpoint is provided instead of connection-string, Fire Arrow Server uses Azure's DefaultAzureCredential chain, which supports managed identity, environment variables, Azure CLI credentials, and other standard authentication methods.
Environment Variable Overrides
| YAML Path | Environment Variable |
|---|---|
fire-arrow.binary-storage.enabled | FIRE_ARROW_BINARY_STORAGE_ENABLED |
fire-arrow.binary-storage.azure.connection-string | FIRE_ARROW_BINARY_STORAGE_AZURE_CONNECTION_STRING |
fire-arrow.binary-storage.azure.container-name | FIRE_ARROW_BINARY_STORAGE_AZURE_CONTAINER_NAME |
fire-arrow.binary-storage.azure.max-file-size | FIRE_ARROW_BINARY_STORAGE_AZURE_MAX_FILE_SIZE |