Skip to main content

Delegated Access with $drop-privilege

$drop-privilege lets a broadly privileged caller obtain a short-lived token that is scoped down to a single target identity — and that can never grant more access than the caller already had. It is designed for services that hold wide access but need to hand a narrowly-scoped credential to a less-trusted component.

A typical example: a backend Device identity with access across many organizations needs to perform work on behalf of one patient. Instead of passing its own powerful token to a downstream worker, it drops privilege to Patient/123 and passes the resulting token, which can only see and touch what both the device and that patient are allowed to.

Available since Fire Arrow Server 1.14.0

$drop-privilege requires authentication to be enabled and the API token provider to be enabled (API_TOKENS_ENABLED=true), because the minted token is a Fire Arrow fa_ token.

Requesting a Dropped-Privilege Token

The caller issues a server-level operation:

POST /fhir/$drop-privilege HTTP/1.1
Authorization: Bearer <jwt>
Content-Type: application/fhir+json

with a Parameters body:

{
"resourceType": "Parameters",
"parameter": [
{ "name": "fhir_identity_reference", "valueString": "Patient/123" },
{ "name": "expires_at", "valueInstant": "2026-07-20T10:15:00Z" }
]
}
ParameterRequiredDescription
fhir_identity_referenceYesThe target identity to scope the token to, e.g. Patient/123.
expires_atNoRequested expiry instant. Capped as described in Token lifetime.

The response is an RFC 8693-style Parameters resource:

{
"resourceType": "Parameters",
"parameter": [
{ "name": "access_token", "valueString": "fa_abc123def456..." },
{ "name": "token_type", "valueString": "Bearer" },
{ "name": "expires_in", "valueInteger": 300 },
{ "name": "fhir_identity_reference", "valueString": "Patient/123" },
{ "name": "on_behalf_of", "valueString": "Device/456" }
]
}
FieldDescription
access_tokenThe short-lived dropped-privilege token (fa_ prefix).
token_typeAlways Bearer.
expires_inToken lifetime in seconds.
fhir_identity_referenceThe target identity the token is bound to.
on_behalf_ofThe original caller's FHIR reference, recorded for audit.

The returned token is then used like any other bearer token:

GET /fhir/Patient/123 HTTP/1.1
Authorization: Bearer fa_abc123def456...

No Privilege Widening

The central guarantee is that a dropped-privilege token can never grant more than the caller already had. At use time, every request made with the token is authorized as the intersection of two rule sets:

  • the target identity's rules — for example, the patient-compartment rules for Patient/123, and
  • the original caller's rules — the rules of the on_behalf_of identity that minted the token.

A request is allowed only if both rule sets allow it; if either denies, the request is denied.

For example, if the target patient's rules would permit updating a resource but the calling device has read-only access, the dropped token cannot update — the caller's constraint applies. Search results are narrowed the same way: the token returns only resources that satisfy both rule sets.

Who Can Call It

$drop-privilege is a JWT-only operation. Callers presenting an API token (fa_ / fo_) receive 403 Forbidden, and the caller's JWT must carry an exp claim.

Minting a token is gated in two steps:

  1. Operation permission. The caller must have an authorization rule granting the drop-privilege operation on the target resource type.
  2. Resource access. The caller must additionally be authorized to update the specific target resource instance under its own rules — the check that answers "can this caller reach this resource at all?"

To grant the operation, add a rule alongside your other authorization rules (see Authorization concepts):

fire-arrow:
authorization:
validation-rules:
- client-role: Device
resource: Patient
operation: drop-privilege
validator: LegitimateInterest

The resource field must name a concrete identity resource type (Patient, Practitioner, Device, or RelatedPerson).

Token Lifetime

Dropped-privilege tokens are deliberately short-lived. The issued lifetime is the minimum of:

  • the requested expires_at (or the configured default when omitted),
  • the caller's JWT exp claim — the token never outlives the JWT that authorized it, and
  • the configured maximum.

If the caller's JWT is close to expiring, the dropped token is correspondingly short; the caller refreshes its JWT and mints a new token.

Configuration

The settings live under the API token provider and are only needed if you use the operation:

fire-arrow:
authentication:
providers:
my-tokens:
type: api-token
enabled: true
api-token:
drop-privilege-default-expiration-minutes: 5
drop-privilege-max-expiration-minutes: 15
drop-privilege-cleanup-after-days: 14
PropertyDefaultDescription
drop-privilege-default-expiration-minutes5Lifetime applied when the caller does not request one.
drop-privilege-max-expiration-minutes15Upper bound on any dropped token's lifetime.
drop-privilege-cleanup-after-days14How long expired dropped tokens are retained for audit before deletion.

The supporting database columns are added automatically by Flyway on the first startup after upgrade; no operator action is required.