CH UMZH Connect IG (R4)
1.0.0-cibuild - ci-build
CH UMZH Connect IG (R4), published by UMZH. This guide is not an authorized publication; it is the continuous build for version 1.0.0-cibuild built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/umzhconnect/umzhconnect-ig/ and changes regularly. See the Directory of published versions
This page is informative — optional guidance that adds no conformance requirements. It illustrates possible ways to satisfy the authorization and client-authentication models defined normatively on the Security page; conforming systems may adopt other mechanisms that meet the same requirements.
The Security page defines the UMZH-Connect authorization model: workflow context is communicated via authorization_details at the token endpoint and reflected as a fhirContext claim in the issued JWT. The actual enforcement of that context — verifying that requested resources fall within the authorized graph — is left to each party's implementation.
In general it should be mentioned that fine-grained authorization may be a very complex task to perform on the standard FHIR API due to a variety of factors, such as a broad range of search parameters covered by standard FHIR APIs. This is quite well covered in the Google FHIR Info Gateway project. Our general approach is to whitelist only the necessary endpoints and parameters required to enable our use case. The complexity of the authorization enforcement is therefore essentially reduced.
This section describes one recommended implementation pattern using a FHIR Consent resource as a local access-control record.
When a workflow object is created — a ServiceRequest on the Placer's side, or a Task on the Fulfiller's side — the hosting party creates a corresponding FHIR Consent resource on their own FHIR server. The Consent:
Consent.provision.data with meaning = "related", capturing the full resource graph in scopeConsent.provision.actorConsent.provision.period.endConsent.status = inactiveExample — Placer creates a Consent authorizing the Fulfiller to access the ServiceRequest graph:1
{
"resourceType": "Consent",
"status": "active",
"provision": {
"period": {"end": "2026-12-31"},
"actor": [
{
"reference": {"reference": "https://registry.example.org/fhir/Organization/fulfiller-org"}
}
],
"data": [
{
"meaning": "related",
"reference": {"reference": "ServiceRequest/sr-123"}
}
]
}
}
The meaning = "related" value means the Consent covers the referenced ServiceRequest and all resources it transitively references — exactly the graph the policy engine must enforce. It is recommended to define a FHIR profile for these kinds of consents.
When the Resource Server receives an API request carrying a JWT with a fhirContext claim, the policy engine resolves the context reference to the corresponding Consent:
GET /Consent?data=ServiceRequest/sr-123&status=active
If an active Consent is found and token.extensions.umzhconnect.organization_reference matches Consent.provision.actor.reference, and the Consent hasn't expired, the request is permitted for any resource within the ServiceRequest graph. If no active Consent exists — because it was never created, has expired, or has been revoked — the request is denied.
FHIRpath equivalent:
Consent.where(
status = 'active'
and provision.data.reference.reference.where(matches('(^|/)' + %context + '$')).exists()
and provision.actor.reference.reference.where(matches('(^|/)' + %party_id + '$')).exists()
and (provision.period.end.empty() or provision.period.end >= now())
).exists()
where %context is the fhirContext reference from the access token and %party_id is the party_id claim. The matches('(^|/)…$') form tolerates references stored as either relative (ServiceRequest/sr-123) or absolute (https://placer.example/fhir/ServiceRequest/sr-123) URLs. It assumes literal, non-versioned references; versioned (/_history/…), urn:uuid:, logical (identifier-based), or contained (#…) references require normalizing the stored reference on write, after which a plain = comparison suffices.
Set Consent.provision.period.end to the date after which access should no longer be granted. The policy engine checks the period as part of its evaluation. No token invalidation is required — expired Consents simply return no results on the query.
To revoke access immediately, set Consent.status = inactive. The next policy engine query for that context will find no active Consent and deny the request.
Parties using short-lived token caches should ensure cache TTLs are short enough to propagate revocation in a timely manner.
FHIR Consent is designed primarily for patient consent to data use. Its application here as a local inter-system access-control record is pragmatic: the semantics of provision.data.meaning = "related" align naturally with the graph-based enforcement model, and the lifecycle fields (expiration, status) map cleanly onto standard Consent elements. Parties are free to adopt alternative enforcement mechanisms as long as they honour the fhirContext claim from the access token as the authoritative context identifier.
The Security page defines private_key_jwt as the production baseline for client authentication. UMZH-Connect additionally supports a staged model: a lighter rung below the baseline to lower the barrier for early pilots, and a higher-assurance rung above it for high-risk scenarios. The authorization model and APIs are identical across all rungs — only the client-authentication method changes. This section describes the full ladder and the governance rules for choosing a rung; it is deployment guidance, not a change to the wire protocol.
As the basic client credentials flow is subject to a number of security weaknesses, we define a stepwise security up-leveling approach for client authentication. Initial integrations may start with basic client credentials to enable rapid onboarding and piloting. As participants move to production and access higher-risk scopes, authentication is upgraded to private_key_jwt, replacing shared secrets with asymmetric keys registered during onboarding — without requiring a central PKI. For the highest-assurance scenarios, the ecosystem supports mutual TLS (mTLS), strengthening client identity binding and reducing token replay risks. This staged model preserves a consistent authorization flow while providing a clear, operationally manageable path to stronger security: partners can join quickly with minimal operational overhead, and then adopt stronger mechanisms when justified by risk, regulatory requirements, or production needs.
client_id + shared secret used for token endpoint authentication.Note: Level 1 is intentionally not SMART Backend Services conformant — Backend Services mandates
private_key_jwt. Shared-secret authentication is offered only as a pilot rung to lower the barrier to first integration; SMART Backend Services conformance is reached at Level 2.
private_key_jwt (baseline)The production baseline, defined normatively on the Security page: the client registers its public key / JWKS with the Authorization Server at onboarding and authenticates to the token endpoint by signing a JWT assertion with the private key. No shared secrets; cleaner key rotation; improved proof-of-possession; SMART Backend Services conformant. Operationally it requires JWKS registration, a rotation procedure, and key rollover support.
| Level | Client authentication | When to use | Security benefits | Operational footprint |
|---|---|---|---|---|
| 1 | Basic client credentials (shared secret) | Sandbox, PoC, low-risk scopes, early pilots | Quick start; baseline access control | Secret distribution + rotation; higher blast radius if leaked |
| 2 | private_key_jwt (JWKS registered at onboarding) |
Production default; medium/high-risk scopes; external partners | No shared secrets; stronger client proof; easier key rotation | Manage JWKS + key rollover; validate signed assertions |
| 3 | mTLS (optionally sender-constrained tokens) | Highest-risk scopes; regulated workflows; large-scale ecosystem | Strong client identity binding; replay resistance | Certificate lifecycle + trust model; revocation/rotation processes |
Use policy triggers to make the ladder actionable and predictable. The goal is to avoid "security by negotiation" and keep onboarding consistent.
Mandate Level 2 (private_key_jwt) when any of the following applies:
Mandate Level 3 (mTLS) when any of the following applies:
Scope-based mapping — a possible mapping:
The generic client credentials flow has potential security weaknesses. The main risks are:
At Level 3 (high-risk), employing mTLS cryptographically binds the token (or at least the session) to the client's TLS certificate, so the token is only usable when presented over a TLS connection that proves possession of the matching private key.
mTLS and other additional security enhancements are included in the definition of OpenID FAPI 2.0 in order to mitigate these risks by adding standardized measures defined by RFCs (RFC 5280, RFC 8705, RFC 6749, RFC 7519). In essence it defines how to
FAPI 2.0 enforcement adds requirements to classical certificate management with PKI infrastructure. Reference implementations (like Denmark) make use of a central PKI infrastructure and certificate issuance and signing, which reduces client-side complexity (trust store etc.) but requires central trust and carries single-point-of-failure risk.
This section positions the UMZH-Connect security concept against three reference profiles that target overlapping problem spaces. The single architectural choice that distinguishes UMZH-Connect from all three is context-bound tokens: every access token is issued for one specific workflow object (a ServiceRequest or Task) carried in the JWT as a fhirContext claim, derived from an RFC 9396 authorization_details request. None of the reference profiles standardize this per-request binding.
References:
| Aspect | UMZH-Connect | SMART Backend Services v2 | HL7 FAST UDAP | CH EPR ITI-71 (IUA) |
|---|---|---|---|---|
| Primary scope | M2M, per-workflow context | M2M, pre-authorized scopes | M2M + user via Tiered OAuth | M2M + healthcare professional / assistant |
| Trust onboarding | Bilateral JWKS at onboarding; mTLS w/ open CA for high assurance | Out-of-band pre-registration | UDAP Dynamic Client Reg + community X.509 CA | Per-CH-EPR policy; registered actors |
| Client auth | private_key_jwt (JWKS at onboarding); mTLS option for high assurance |
private_key_jwt mandatory |
private_key_jwt w/ UDAP cert; mTLS option |
private_key_jwt + HTTP Message Signatures (RFC 9421) |
| Scope vocabulary | SMART system/* in scope |
SMART system/* in scope |
SMART-compatible + UDAP extensions | Profile-specific (launch, EPR scopes) |
| Per-request workflow context | RFC 9396 + fhirContext JWT claim |
Not addressed | Not addressed | Not addressed |
| Caller-organization identity | extensions.umzhconnect.organization_reference (registry URL) — follows IHE IUA extensions container pattern |
Not standardized | UDAP B2B hl7-b2b extension (organization_id, organization_name, purpose_of_use) |
extensions.ihe_iua + extensions.ch_epr |
| User identity in M2M | Not in scope | Out-of-band for user//patient/ |
Tiered OAuth → user's OIDC IdP | Mandatory subject_name, subject_role, purpose_of_use |
| Token format | JWT | JWT | JWT | JWT only (JWE forbidden) |
| Hardening reference | FAPI 2.0 (high-assurance option) | OAuth 2.0 BCP | UDAP profiles + cert policies | OAuth 2.1 + RFC 9421 |
The example shows only the fields relevant to context enforcement. FHIR mandates additional elements — Consent.scope and Consent.category in R4, and a role on each provision.actor — which must be populated for a valid resource; how they are coded is a local concern left to each implementor. ↩