docs(authorization): add Authorization Information Model draft - #109
docs(authorization): add Authorization Information Model draft#109stevenvegt wants to merge 8 commits into
Conversation
Document the current authorization frameworks in Dutch healthcare data exchange (AORTA, MedMij, Twiin, Nuts use-case communities) using a shared three-layer model, and from that derive a candidate consistent OAuth 2.0 scope convention at the use-case level. The chapter introduces TrustFramework, AuthenticationProfile, AuthorizationPolicy, the delegation chain, identity claims, and the access-token-request artefacts. PlantUML diagrams cover the Nictiz information model, the layer-2 trust-framework model, the layer-3 OAuth wire, and an AS evaluation flow. Triggered by the LSP x Nuts LDN effort; intended as a praat-plaat for review.
Holds manual copies of the diagram sources as a restore point while iterating on diagram layout. Assisted-by: AI
Splits the layer 2 into 2 views: credentials and the autorizations. Adds the concept of a prerequisite which gates the roles. Changes the primary scope from use-case back to transactions. Adds a full medication request example.
Reframe the problem as framework-local models without a shared national vocabulary; the wire-grammar divergence is the symptom, not the disease. Restructure into model / specification / adoption / design notes, with the rationale (scope-unit choice, enforcement topology and evidence, delegation lifetimes, layer-2 derivation) moved out of the main line. Model changes: English terms for the Nictiz catalogue concepts with a translation table; Operation moved from layer 1 to the realisation layer; PermissionMatrix always present (trivial allow-all when no policy exists, absent entry is deny); QualifiedSystemRole as optional coverage refinement for coarse system roles; Membership claim for organisational admission; HCP-to-HCO delegation conditional on under-mandate use; patient channel modelled; tx claim demoted to MAY (scope carries the transaction token). Verified against ART-DECOR via the REST API: beschikbaarstellen is the source side of a pull exchange (type back), not an index publish. Diagrams: corrected layer-1 model, layer-1-to-layer-2 bridge, symmetric two-pipeline role resolution; layer-2 credential row layout; kramdown table classes reattached so tables render with grid borders. Assisted-by: AI
Adopt concern-based layer names: information layer (L1), trust layer (L2), realisation layer (L3). The <<Nictiz layer>> stereotype named an organisation, contradicting the page's own "a layer groups concerns, not authors"; diagrams now stereotype foreign entities by layer name. Layer-2 diagram rebuilt: actors, claims, and information-layer roles in three rows, claims typed by <<IdentityClaim>>/<<ContextClaim>> stereotypes instead of six inheritance arrows to abstract boxes, and a direct "serves" relation between ServiceProvider and organisation. Layer-1 diagram relaid: data branch left, transaction branch right. The role-resolution section is restructured around the two pipelines (business-role and system-role, replacing "professional/system side"), with real h5 headings for the layer-2 views, bold lead-ins for the two pipelines only, and an inline matrix-slice illustration table. Prose pass applied throughout: flourishes removed, dense sentences split. Example tables simplified and kramdown grid classes reattached so they render with borders. Assisted-by: AI
|
Shouldn't this be output from a working group/werkpakket of the Technische Kring? |
|
The very AI-tone-of-voice-ness of this document makes it very hard for me to understand and thus review; e.g. "minting SMART-on-FHIR scopes". Note that in OAuth, scopes are granted. |
|
|
||
| Dutch healthcare data exchange runs under several authorization regimes (AORTA-on-FHIR, MedMij, Twiin, Nuts use-case communities). Each one has, over time, built its own internal authorization model: its own vocabulary for qualifications, its own delegation structures, its own scope-token grammar, its own way of pairing identity claims with policy. The models overlap conceptually, but never align. Cross-framework integration is therefore expensive and brittle. | ||
|
|
||
| This chapter proposes a shared *authorization information model* and derives one concrete OAuth 2.0 wire convention from it. The model is layered: a layer 1 that adopts the Nictiz "Handleiding Wiki documentatie" structure verbatim, and a layer 2 that adds the authz-specific concepts that the Nictiz model does not address (qualifications, delegations, identity claims, the access token itself). |
There was a problem hiding this comment.
"Handleiding Wiki documentatie" structure verbatim
what?
There was a problem hiding this comment.
and a layer 3?
"the access token itself" I think that's layer 3
| This proposal makes the model explicit. It defines a shared _authorization information model_, layered on top of the Nictiz information-standard catalogue, and derives one concrete OAuth 2.0 wire convention from it. | ||
|
|
||
| The intended audience is architects of the trust frameworks listed above. The proposal is independent of how identity claims are attested and does not prescribe a wire format; the Specification lists the attestation forms in use today. |
There was a problem hiding this comment.
Isn't this contradictory:
and derives one concrete OAuth 2.0 wire convention from it.
...
The proposal is independent of how identity claims are attested and does not prescribe a wire format
|
|
||
| ### Introduction | ||
|
|
||
| Dutch healthcare data exchange runs under several trust frameworks (AORTA-on-FHIR, MedMij, Twiin, Nuts use-case communities). Each one has, over time, built its own authorization model. Each model is well documented within its own framework. But it is framework-local: it lives spread over registry definitions, policy documents, and wire conventions, in a vocabulary that only works inside that framework. No shared national model exists. The models overlap conceptually: qualifications, delegations, roles, and context checks appear in all of them. Yet they never align, and there is no shared vocabulary to compare them in. |
There was a problem hiding this comment.
The "why" is not clear to me. What is the goal for you defining this document? What is our (Kring Techniek) intended end-state of things? Is it "one wire format to rule them all", or will the LDN be a patchwork of interopable networks with each their own protocols?
There was a problem hiding this comment.
The goal is 1) introducing one unifying model for authz which is mostly compatible with existing trust frameworks and cementing the Nictiz information standard model as its basis. 2) proposing a mapping to OAuth so we can all use the same wire format for requesting access tokens.
There was a problem hiding this comment.
Regarding your question about the patchwork, I think the reality is that that always be the case. Networks are in different states of their evolution and are introduced, phased out etc. So lets embrace the patchwork and try to standardize the traffic in between. So internally use your own if you want, but in between, lets standardize.
|
|
||
| Because each model is stated only in its own framework's terms, the models cannot be compared, mapped, or composed. A developer building a system that participates in two frameworks must assemble two complete models from documentation scattered across wikis, registries, and policy documents, and invent the mapping between them. A policy author cannot tell whether two frameworks make the same access decision for the same situation. This is the core problem: cross-framework integration is expensive and brittle. | ||
|
|
||
| The divergence is most visible on the OAuth wire: each framework identifies the authorized work in the request scope with a different grammar, and differs in whether that identification survives onto the issued access token. The wire divergence is only the visible part: the grammars differ because each framework derived its wire convention from a different underlying model. Aligning the syntax without aligning the model would change nothing. This proposal therefore defines the model first, and the wire convention as its consequence. |
There was a problem hiding this comment.
I'd say not OAuth wire per se, but more on different trust/governance and completely different protocols (SAML/OAuth). If it were only OAuth wire format...
| - **Role resolution**: every framework maps presented identity claims (rolcodes, organisation identifiers) onto something it permits actions for, but the mapping rules are buried in framework-specific policy documents such as the Autorisatierichtlijn, with no common structure. | ||
| - **Context checks**: consent (Mitz), the treatment relationship, and purpose-of-use gates exist everywhere, attached at different points in each framework and with no shared vocabulary (an explicit purposeOfUse field in the Nuts authorization credential, the distinct spoed situation in Mitz). | ||
|
|
||
| Because each model is stated only in its own framework's terms, the models cannot be compared, mapped, or composed. A developer building a system that participates in two frameworks must assemble two complete models from documentation scattered across wikis, registries, and policy documents, and invent the mapping between them. A policy author cannot tell whether two frameworks make the same access decision for the same situation. This is the core problem: cross-framework integration is expensive and brittle. |
There was a problem hiding this comment.
"This is the core problem: cross-framework integration is expensive and brittle." stated like this sounds like it's only an authorization problem
|
|
||
| The information-layer entity (`Transaction`) appears in yellow; trust-layer entities (`IdentityClaim`, `ServiceProvider`) in blue; realisation-layer entities, including the `Operation` and `FHIRResource`, in green. | ||
|
|
||
| - **AccessTokenRequest**: what the ServiceProvider sends to the AS. Carries one transaction scope token (the `tx`), an optional list of operations (interactie-ids) that narrow the minted scopes, the asserted identity claims, and the context claims. The `patient` attribute carries the data-subject BSN where the transaction concerns a patient; the AS enforces that the patient identifier in the eventual query equals the issued token's `patient` scope. |
| - A RolePrerequisite SHALL resolve presented identity claims to an AuthorizationRole, which refines exactly one business role; a role MAY have several RolePrerequisites, and satisfying any one is sufficient. | ||
| - A SystemRolePrerequisite SHALL resolve a ServiceProvider's claims to a QualifiedSystemRole. A QualifiedSystemRole refines exactly one system role and covers one or more of the transactions that use that system role. Absent an explicit refinement, the QualifiedSystemRole SHALL default to the system role itself, covering all of that system role's transactions. | ||
| - Every trust framework SHALL publish a PermissionMatrix per use case, mapping (AuthorizationRole, Transaction) to allow or deny plus a delegatable flag. The matrix MAY be trivial (an explicit allow for every resolved AuthorizationRole), but SHALL NOT be absent; the absence of an entry SHALL be treated as deny. | ||
| - A trust framework MAY require a Membership claim (organisational admission to the framework or an information standard) for the HealthcareOrganization; prerequisites reference it like any other identity claim. |
There was a problem hiding this comment.
what about non-healthcare organizations? Out of scope?
| > | ||
| > **REQ-3 (MAY).** The request scope MAY contain operation tokens (interactie-ids), each one belonging to the scoped transaction's realisation, to narrow the minted scopes for least-privilege. | ||
| > | ||
| > **REQ-4 (SHALL).** The AS SHALL reject any operation token that does not belong to the scoped transaction's realisation. |
There was a problem hiding this comment.
"scoped transaction's realisation"?
|
|
||
| > **REQ-5 (SHALL).** The transaction scope token SHALL appear in the AT's `scope` alongside the minted SMART on FHIR scopes. The `scope` member is standard in both JWT access tokens and introspection responses, so the transaction identifier is visible to the resource server and the audit subsystem without any non-standard field. | ||
| > | ||
| > **REQ-6 (MAY).** The AT MAY additionally carry the transaction token as a dedicated `tx` claim, for consumers that prefer not to parse `scope`; when present, its value SHALL equal the token in `scope`. |
There was a problem hiding this comment.
then why not use "scope", conforming OAuth?
There was a problem hiding this comment.
Agreed; the dedicated tx claim (old REQ-6) is dropped in c734d94. The transaction identifier lives only in scope.
| > - the ServiceProvider's claims (its Qualification and the ServiceProvider delegation) resolve, via a SystemRolePrerequisite, to a QualifiedSystemRole whose coverage includes the scoped transaction; | ||
| > - the presented identity claims resolve, via a RolePrerequisite, to an AuthorizationRole that the PermissionMatrix permits for the transaction; | ||
| > - if the AuthorizationRole is exercised under mandate (defined as: the organisation acting unattended, or a user acting under the professional's responsibility), then (a) the PermissionMatrix entry SHALL be delegatable, and (b) a HealthcareProfessional-to-HealthcareOrganization delegation SHALL authorize the business role the AuthorizationRole refines; | ||
| > - the context gate passes (consent, treatment relationship, purpose-of-use, where required). |
There was a problem hiding this comment.
in Nuts, this is done during runtime. Should we make this mandatory on the AS side? Or make it more lenient, to allow the Resource Server to make these authz decisions if more applicable in particular use cases?
There was a problem hiding this comment.
I think we were already moving to a hybrid model, since once we accept the SMART-on-FHIR route as a valid authz scheme, you need to check a lot before you can grant a scope. But I think there will always be data-state specific runtime checks needed.
In our nuts-node we were toying with the AT request callback to a auhz endpoint which returned the granted scopes, this would be a good fit for that I think.
For existing nuts applications with more use-case identifiers, we can issue them based on the identity claims and do the rest on runtime.
I'm not sure if the resource server should make authz decisions, but if you mean that a PDP does it before forwarding to the RS, that was the original model right, and should be fine.
There was a problem hiding this comment.
Agree that it is hybrid. I want to make the split explicit in the spec, because REQ-8 as written contradicts the "enforcement topology" section:
- Identity and permission checks (qualification, delegations, role resolution, matrix, mandate) happen at issuance, at the AS. Not because a runtime party could not redo them (with claims in the AT it could), but because of what granting the scope means: the AT carries the tx token in its scope, and granting it asserts that the authorization decision was made. The holder of an AT should be able to expect it to work, with runtime failures limited to checks whose inputs did not exist at issuance: data state and tx-specific details. This expectation is the rule I want to state in the spec, and the REQ-8 split falls out of it.
- The context gate (consent, treatment relationship, purpose of use) must be enforced before data is released, but the enforcement point becomes a topology choice: at issuance by default, or deferred to a PDP/RS at runtime.
- Data-state rules ("the receiver may only move this Task from requested to accepted") have no place in the current text. They can only be evaluated by the party holding the state, so they are runtime rules at the RS. I intend to add them as a named rule kind in the realisation catalogue instead of leaving them implicit.
Concretely: I will split REQ-8 into an issuance-time part and a deferrable part, adjust REQ-9 accordingly, and extend the enforcement topology section. And you are right on the other comment that this reworks part of the PDP model on the authorization page I will make the relation explicit there.
There was a problem hiding this comment.
Implemented in c734d94: REQ-7 keeps identity and permission checks at issuance; REQ-8 requires the trust framework to declare, per use case, each context check's enforcement point: AS at issuance, AS at introspection, or a PDP at the resource server. State rules (e.g. Task status transitions) got a named place, always enforced by the resource server. The governing principle is now in the text: an issued AT is accepted as-is at runtime except for checks whose inputs did not exist at issuance.
|
|
||
| By adhering to these principles, this Implementation Guide supports consistent and secure authorization, fostering improved interoperability within the healthcare ecosystem. | ||
|
|
||
| See [Authorization Information Model](authorization-model.html) for the proposed shared authorization model across trust frameworks, including the use-case scope convention for OAuth 2.0 access tokens. It complements the policy input data model defined below. |
There was a problem hiding this comment.
I think it partly replaces/reworks it, because the proposed model moves all checks (except checking that the request conforms the granted FHIR scope) to AT-issuance-time.
There was a problem hiding this comment.
Reworded exactly along your line: the page now says the model partly reworks the PDP picture, and the policy evaluation below remains as a runtime enforcement point to which a framework can assign context checks and state rules.
Yes, as in sort of and in a form it is. It is the result of the architectural effort of the LSPxNuts project and this is/should be under responsibility of the kring techniek. However, it is/was mainly assigned to me. I want to propose a sub-kring "architecture" and make it the responsibility of that kring instead of one person (me). |
After review on PR 109: REQ-7/REQ-8 now separate issuance-time identity and permission checks from context checks whose enforcement point the trust framework declares per use case (issuance, introspection, or a PDP at the resource server). State rules from the information-standard lifecycle get a named place, enforced by the resource server. Scopes are granted (not minted), "token" is reserved for the access token, and the context gate is renamed to context checks. Assisted-by: AI
Reworked the chapter in c734d94. Scopes are now granted and tokens issued throughout; "minting", "the context gate degenerates", and similar phrasing are gone. Terminology now reserves "token" for the access token; the scope entries are transaction and operation identifiers. |
Review pass on the authorization model page: align the MedMij example slug, split query-BSN enforcement between the AS (binds the patient attribute) and the RS (checks the query against it), deduplicate REQ-9 and REQ-10 against REQ-7/8, lowercase RFC keywords outside normative rules, move the REQ-5 rationale out of the requirement, and reorder the glossary. Model changes settled in review: all delegations are one mechanism distinguished by duration and payload; the acting user's session reaches the AS as a new UserAssertion identity claim; and the professional-to-organisation delegation carries the delegator's identifier and rolcode, because under an unattended mandate it is the only claim that brings them. Assisted-by: AI
The request now carries only the transaction identifier: the requester states its intent in layer-1 vocabulary, the AS translates it into granted SMART on FHIR scopes via the realisation catalogue, and the client never needs the operation grammar. Narrowing by operation had no policy meaning (permission is decided per transaction) and tied the request format to the FHIR realisation. A design note records the rejected alternative and the AORTA migration consequence: interactionId scope entries are replaced by the transaction identifier, not joined. Consequences: REQ-3/REQ-4 removed and the remaining requirements renumbered to REQ-1..8, the operation identifier appendix deleted, Operation redescribed as a realisation concept (FHIR interactions on the zib-to-FHIR profiles) instead of a wire construct, and the layer-3 and evaluation diagrams updated. The layer-3 diagram gains the SoFScope-to-Operation derivation edge and a compact two-row layout. Also rewords "grain" phrasing. Assisted-by: AI
Build: https://build.fhir.org/ig/nuts-foundation/nl-generic-functions-ig/branches/add-authorization-information-model/authorization-model.html
Summary
Intended as a praat-plaat for review with the trust frameworks before any normative use. Kept in draft so the FHIR IG build can render the diagrams and the resulting page can be shared for discussion.
What is in the chapter
Test plan