Skip to content

docs(authorization): add Authorization Information Model draft - #109

Draft
stevenvegt wants to merge 8 commits into
mainfrom
add-authorization-information-model
Draft

docs(authorization): add Authorization Information Model draft#109
stevenvegt wants to merge 8 commits into
mainfrom
add-authorization-information-model

Conversation

@stevenvegt

@stevenvegt stevenvegt commented May 21, 2026

Copy link
Copy Markdown
Member

Build: https://build.fhir.org/ig/nuts-foundation/nl-generic-functions-ig/branches/add-authorization-information-model/authorization-model.html

Summary

  • Documents the current authorization frameworks used in Dutch healthcare data exchange (AORTA, MedMij, Twiin, Nuts use-case communities) using a shared three-layer model
  • From that shared model, derives a candidate consistent OAuth 2.0 scope convention at the use-case level
  • Triggered by the LSP x Nuts LDN effort

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

  • Three-layer information model with PlantUML diagrams: Nictiz information standards (layer 1), trust framework (layer 2), OAuth wire artefacts (layer 3)
  • Entities introduced at layer 2: TrustFramework, AuthenticationProfile, AuthorizationPolicy, the delegation chain (HCP-to-HCO at bedrijfsrol level; HCO-to-ServiceProvider at systeemrol level), Qualification, IdentityClaim with concrete subtypes
  • Entities at layer 3: AccessTokenRequest, AccessToken, SoFScope
  • Candidate use-case scope token format: `.uc...`
  • Operation token format following the AORTA-on-FHIR interactietabel: `::`
  • Normative REQs (REQ-1 through REQ-10) for the AT request, the issued AT, and AS behaviour
  • Happy-path AS evaluation flow diagram with per-step inputs annotated (R for request inputs, L1 for Nictiz lookups, L2 for trust-framework registry)
  • Worked examples for MedMij and AORTA professional flows as RFC 7662 token-introspection responses

Test plan

  • FHIR IG build succeeds and renders the page under Authorization in the left-hand TOC
  • All four PlantUML diagrams render as SVG on the page
  • References resolve

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.
@stevenvegt
stevenvegt requested a review from reinkrul May 21, 2026 13:27
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
@reinkrul

reinkrul commented Jun 15, 2026

Copy link
Copy Markdown
Member

Shouldn't this be output from a working group/werkpakket of the Technische Kring?

@reinkrul

reinkrul commented Jun 15, 2026

Copy link
Copy Markdown
Member

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).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Handleiding Wiki documentatie" structure verbatim

what?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and a layer 3?

"the access token itself" I think that's layer 3

Comment on lines +11 to +13
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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is send as 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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"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`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then why not use "scope", conforming OAuth?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread input/pagecontent/authorization.md Outdated

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@stevenvegt

Copy link
Copy Markdown
Member Author

Shouldn't this be output from a working group/werkpakket of the Technische Kring?

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
@stevenvegt

Copy link
Copy Markdown
Member Author

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".

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.

@stevenvegt
stevenvegt requested a review from reinkrul July 17, 2026 13:01
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants