Access Control
Haste Health implements fine-grained access control using AccessPolicyV2 resources. These policies provide attribute-based access control (ABAC) beyond basic OAuth scopes, enabling complex authorization rules based on user identity, resource properties, and request context.
AccessPolicyV2 Resource
AccessPolicyV2 resources define authorization policies that evaluate against API requests to determine access permissions.
Key Fields
- engine: Evaluation engine (
full-access,rule-engine) - target.link (deprecated): Who the policy applies to. Use
AccessPolicyV2Assignmentinstead - rule: Array of authorization rules with actions, resources, and conditions
- name: Human-readable policy description
Policy Engines
AccessPolicyV2 supports multiple evaluation engines for different authorization models:
Full Access Engine
Engine code: full-access
Grants unrestricted access to all resources and operations. The simplest engine—always returns success.
Use cases:
- System administrators with full platform access
- Automated service accounts needing complete access
- Development/testing environments
Example:
{
"resourceType": "AccessPolicyV2",
"id": "admin-full-access",
"name": "Admin Full Access",
"engine": "full-access"
}
Assign it with an AccessPolicyV2Assignment (see Associating Policies with Users):
{
"resourceType": "AccessPolicyV2Assignment",
"accessPolicy": {
"reference": "AccessPolicyV2/admin-full-access"
},
"link": {
"reference": "Membership/admin-membership"
}
}
Rule Engine
Engine code: rule-engine
Enables fine-grained, attribute-based access control using FHIRPath expressions to define rules and conditions.
Special Variables:
The following special variables are available within FHIRPath expressions for rules and conditions:
user: The authenticated user this includes the user's id.request: The incoming API request details, including method and resource type.level: Whether request is at 'instance', 'type' or 'system' level.type: One of "create"|"read"|"vread"|"update"|"patch"|"delete"|"capabilities"|"search"|"history"|"invoke"|"batch"|"transaction"|"compartment"resourceType: The FHIR resource type being accessed (if applicable).resource: The FHIR resource if present in the request IE (create).id: The resource ID if applicable.parameters: The search parameters if applicable.
Attributes
Attributes are how you can make pull in external data during a policy evaluation. We support 'read', and 'search' operations.
For example
"attribute": [
{
"operation": {
"type": "read",
"path": {
"language": "text/fhirpath",
"expression": "Patient/123"
}
},
"attributeId": "patient"
}
]
This operation will read the Patient with ID 123 and make it available in FHIRPath expressions as %patient.
Rules
Rules define whether or not to permit or deny access based on conditions. Each rule includes:
- effect:
permitordeny - combineBehavior:
all(AND) orany(OR) - target.expression: FHIRPath expression to determine whether or not to evaluate this rule
- condition.expression: FHIRPath expression evaluated if target matches
Example:
{
"resourceType": "AccessPolicyV2",
"name": "Rule Engine",
"engine": "rule-engine",
"rule": [
{
"name": "Access Control",
"combineBehavior": "any",
"rule": [
{
"name": "Is Read request",
"target": {
"expression": {
"language": "text/fhirpath",
"expression": "true"
}
},
"condition": {
"expression": {
"language": "text/fhirpath",
"expression": "%request.type = 'read'"
}
}
}
]
}
]
}
Policy Evaluation
When a user makes an API request:
- Token validation: JWT token verified and claims extracted
- Policy loading: AccessPolicyV2 resources loaded by version IDs in token
- Engine execution: Each policy evaluated using its specified engine
- Decision: If any policy grants access, request proceeds; otherwise denied
Multiple policies can apply to a single user (via Membership). The system uses an "any allow" model—if any policy permits the action, it's allowed.
Associating Policies with Users
Policies are linked to the resources they apply to with AccessPolicyV2Assignment resources. Each assignment has an accessPolicy reference and a link reference to a Membership, ClientApplication or OperationDefinition. Assignments can be created and removed without editing the policy itself.
{
"resourceType": "Membership",
"link": {
"reference": "User/user-789"
},
"role": "member"
}
Then assign the policy to the Membership:
{
"resourceType": "AccessPolicyV2Assignment",
"accessPolicy": {
"reference": "AccessPolicyV2/policy-id"
},
"link": {
"reference": "Membership/membership-id"
}
}
During authentication, the system:
- Finds the user's Membership (or the ClientApplication, for client credentials)
- Searches for
AccessPolicyV2Assignmentresources whoselinkreferences it, and loads the policies they point to - Includes policy version IDs in access token
:::warning Deprecated
AccessPolicyV2.target.link is deprecated. Policies that still use it continue to apply, but new policies should use AccessPolicyV2Assignment.
:::
Best Practices
Principle of least privilege: Grant minimum necessary permissions
- Start with restrictive policies
- Add specific exceptions as needed
Layer policies: Combine multiple policies for flexibility
- Base policy for common permissions
- Specific policies for exceptional access
Test thoroughly: Validate policies before production
- Use
$evaluate-policyoperation - Test edge cases and negative scenarios
Document conditions: Use clear policy names and document complex FHIRPath expressions
Version carefully: Policies are versioned—understand token caching implications
Related Documentation
- Membership: Link policies to users
- Scopes: OAuth scope-based permissions
- AccessPolicyV2: Resource overview
- AccessPolicyV2 Schema: Complete resource reference