# Developer Guide

This guide gives a brief overview of the core Koppeltaal 2.0 concepts and how to integrate with its services

## Document Information

### Copyright Notice

![](https://1577345028-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiVMn-5GzUw-bGYHPT8%2Fuploads%2Fgit-blob-dcc15fd6a92e21ac527032fce03e725afcc37a84%2FShareAlike.png?alt=media)

This document is released under the [Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license](https://creativecommons.org/licenses/by-sa/4.0/).

### Status

This document is in draft.

### Author / contact

[Joris Scharp](mailto:joris@headease.nl)\
[Headease B.V.](https://www.headease.nl/)

## Important differences with Koppeltaal 1.3.x

| Concept                | **KT 1.3.x**                                | KT 2.0                   |
| ---------------------- | ------------------------------------------- | ------------------------ |
| **FHIR Exchange**      | Messaging                                   | RESTful API              |
| **Content Validation** | Separate service                            | Built-in                 |
| **Authorisation**      | None - application has access to everything | On resource & CRUD-level |

### FHIR Exchange

By using the (FHIR) RESTful API exchange there is a single source of truth. Koppeltaal 1.x acted as a message broker, giving each participant the responsibility to keep all data up-to-date.

Another big advantage is that Koppeltaal 2.0 works with small messages. So no self-contained bundles. This saves a lot of data being transferred over the line and the chance of 409 Conflicts are considerably reduced.

### Content Validation

Previously, a separate service could be used to check whether the content of a `Bundle` is valid. However, this validation was not enforced by the Koppeltaal server.

Koppeltaal 2.0 uses [profiles](https://simplifier.net/Koppeltaalv2.0/~resources?fhirVersion=R4). A profile indicates exactly what the rules are per [Resource](https://www.hl7.org/fhir/r4/resourcelist.html). The Koppeltaal server can enforce profiles by validating that the Resources adhere to the profile.

### **Authorisation**

Applications connect to the Koppeltaal server. Within "Domeinbeheer" (Domain Management), roles are assigned to the applications. A role can contain multiple CRUD permissions per Resource. With Koppeltaal 2.0, you are only allowed to work with resources to which you are entitled. With Koppeltaal 1.x, applications can see everything that they are subscribed to within a Domain.

{% hint style="warning" %}
Note: Resources are managed at application level Koppeltaal 2.0.

The golden rule is that the application **itself** determines which resources are accessible at user level within the application.
{% endhint %}

##


# Proof Of Concept

Also known as the Walking Skeleton

Koppeltaal 2.0 has been developed by using an Agile methodology. The devised architecture is tested using POC applications. The applications used within the POC are **not** the applications that will ultimately be used when Koppeltaal 2.0 goes live.

{% hint style="info" %}
Applications within the POC now often use Yivi (formerly known as IRMA) to identify the user and relate across systems. This is not part of the standard. It's likely that Koppeltaal 2.0 will not use Yivi in the production environment.
{% endhint %}

The POC consists of the following type of applications:

| Application type   | Description                                                                                                                                              |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| System component   | Applications that form the core of Koppeltaal 2.0.                                                                                                       |
| Supplier           | A supplier who uses their non-production platform together with the PoC Koppeltaal 2.0 Server.                                                           |
| Pseudo-application | Application that mimics an e-health application. These are removed from the list as they need to be updated with the latest changes in the specification |
| Additional service | Application that is not part of the Koppeltaal standard, but helps during the development.                                                               |

The POC consists of the following applications:

<table><thead><tr><th width="252.33333333333331">Application</th><th width="186">Type</th><th>Description</th></tr></thead><tbody><tr><td>Koppeltaal Server</td><td>System component</td><td>A FHIR HAPI R4 implementation for Koppeltaal.</td></tr><tr><td>Domain Management</td><td>System component</td><td>Applications can register to join a domain. A role is also assigned to applications, which determines what actions the application is allowed to perform on the Koppeltaal Server.</td></tr><tr><td>Auth Server</td><td>System component</td><td>Here - after approval from Domain Management - applications can request an access token via the <a href="https://hl7.org/fhir/uv/bulkdata/authorization/index.html#obtaining-an-access-token">Backend Services Authorization</a> flow.</td></tr><tr><td>Koppeltaal IdP</td><td>System component</td><td>Identity Provider (IdP) used to validate that the launching user matches the logged in user. This essentially prevents tokens from being intercepted and executed.</td></tr><tr><td>Domain Access Test Tooling</td><td>Additional service</td><td>This test suite helps with the implementation of the <a href="https://hl7.org/fhir/uv/bulkdata/authorization/index.html#obtaining-an-access-token">Backend Services Authorization</a>.</td></tr><tr><td>Koppeltaal Test Tooling</td><td>Additional service</td><td>A rich test of tools that help developers implement Koppeltaal. Look at <a href="/technische-howto/koppeltaal-test-tooling">this</a> page for more information.</td></tr></tbody></table>


# Joining a domain

To join a domain, a request can be submitted to [Domain Management](https://domain-admin.koppeltaal.headease.nl/). After logging in to Domain Management, pages for all roles will be displayed (both management and requesting access). Follow these steps to join a domain:

1. Navigate to [Domain management](https://domain-admin.koppeltaal.headease.nl/).
2. Login via the [yivi app](https://www.yivi.app/) on your mobile device.
3. Open the tab "AANVRAAG INDIENEN"
4. Enter the name of you application and its corresponding [JWKS endpoint](/technische-howto/connectie-maken-met-koppeltaal/requirements/jwks-opzetten).
5. Submit the request.
6. Open the tab "OVERZICHT".
7. Assign a role to your newly created application.
8. Change the status to `Approved`.
9. Use the `client_id` in your application to execute a [SMART Backend Service](/technische-howto/connectie-maken-met-koppeltaal/toegang-tot-koppeltaal) request.

{% hint style="info" %}
Koppeltaal recommends all applications to use JWKS endpoints when requesting an `access_token`.

When applications are tested locally, it is difficult to use JWKS. In that case it is also possible to simply register a public key in PEM format. [This](https://github.com/Koppeltaal/Koppeltaal-2.0-Generate-KeyPair/) project can be used to quickly generate a usable key pair for the Koppeltaal POC components.

To test using JWKS locally, handy tools such as [ngrok](https://ngrok.com/) can be used.
{% endhint %}

## Topics

[TOP-KT-019 - Beheer](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27119214/TOP-KT-019+-+Beheer)


# Role-based access control

The following pages explain step by step what the authorization model looks like and how it can be managed in the form of roles.


# Autorisation model

Koppeltaal 2.0 has an authorisation model. This means that an application cannot simply see all data in a domain. What can be viewed is determined with the authorisation model.

## 1. Authenticate

When an application has [joined a domain](/domain-access/domein-toetreden), the application will have been assigned a `client_id`. This `client_id` is included in the `access_token` that is required to communicate with the Koppeltaal server. This way, the Koppeltaal server knows which application is performing a request and therefore the associated permissions.

## 2. Resource ownership

The Koppeltaal server automatically adds a `resource-origin` extension to every `DomainResource` that is created. This extension references to a specific `Device` resource that has a 1-on-1 relation with the `client_id`. This way, the origin of a resource can always be found. This is an essential part of the authorisation model.

## 3. Role and permissions

Every application in a domain is assigned a single role. A role maps to multiple permissions. A permission has the following 3 properties:

### Resource

A permission always applies to a single [FHIR Domain Resource](https://www.hl7.org/fhir/r4/domainresource.html#bnr).

### Action

A CRUD-level (create, read, update, delete) action.

### Scope

The `resource-owner` scope. The following scopes are supported:

| Scope   | Description                                                                                                                                        |
| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| Own     | The permission only applies to resources (selected resource type of the permission) whose `resource-origin` matches the authenticated application. |
| All     | The permission applies to all resources (selected resource type of the permission) in the domain.                                                  |
| Granted | The permission applies to resources (selected resource type of the permission) whose `resource-origin` matches the selected application(s).        |

## Topics

[TOP-KT-005a - Rollen en rechten voor applicatie-instanties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123707/TOP-KT-005a+-+Rollen+en+rechten+voor+applicatie-instanties)


# Creating a role

A video that shows how to assign a role and how to create a new role with specific permissions

{% hint style="info" %}
Permissions bound to a role are set as OAuth scopes on the `access_token` used to communicate with the Koppeltaal server. Therefore, the `access_tokens` should be short lived. Revoking a permissions will not be instantly applied.
{% endhint %}

{% embed url="<https://drive.google.com/file/d/1KPeYBPs0pvOvYhsjiOtCJfDj_K6evk6c/view>" %}
Rol aanmaken binnen domeinbeheer
{% endembed %}

## Topics

[TOP-KT-019 - Beheer](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27119214/TOP-KT-019+-+Beheer)


# Search Narrowing

{% hint style="info" %}
Permissions bound to a role are set as OAuth scopes on the `access_token` used to communicate with the Koppeltaal server. Therefore, the `access_tokens` should be short lived. Revoking a permissions will not be instantly applied. This can take up to 5 minutes.
{% endhint %}

When an application is allowed to read resources with an `Own` or `Granted` scope, it means that not all resources are allowed to be returned by the Koppeltaal server. To keep this as simple as possible for platforms that use Koppeltaal, "Search Narrowing" will be applied to these requests. Search narrowing means that the client can simply request `GET /Patient` to retrieve "all" `Patient` resources. The Koppeltaal server ensures that only the `Patient` resources for which the application is authorised are returned.

{% embed url="<https://drive.google.com/file/d/1bJFTUdJPhLLOxm-iSk33K8raf9Ebm3JN/view>" %}
Search Narrowing
{% endembed %}

## Topics

[TOP-KT-005a - Rollen en rechten voor applicatie-instanties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123707/TOP-KT-005a+-+Rollen+en+rechten+voor+applicatie-instanties)

[TOP-KT-002b - Search interacties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27125775/TOP-KT-002b+-+Search+interacties)


# Revoke Permission

{% hint style="info" %}
Permissions bound to a role are set as OAuth scopes on the `access_token` used to communicate with the Koppeltaal server. Therefore, the `access_tokens` should be short lived. Revoking a permissions will not be instantly applied. This can take up to 5 minutes.
{% endhint %}

When there is no permission for a `DomainResource` & CRUD action, the application will, by definition, not be allowed to perform this action. Below is a demonstration of what happens when the `Read` permission is removed:

{% embed url="<https://drive.google.com/file/d/1HzlgpKz7TLkLNnNmuhJ_KCKkWgxr_j2O/view>" %}
Revoke Permission
{% endembed %}

## Topics

[TOP-KT-019 - Beheer](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27119214/TOP-KT-019+-+Beheer)


# Koppeltaal Test Tooling

The interactive developer guide

The [Koppeltaal Test Tooling](https://testsuite.koppeltaal.headease.nl/) can be seen as an interactive dev-guide. It offers a rich set of tools that help developers implement Koppeltaal. It can visualize many of the technical how-to items from this developer guide.

It can be used to test the common Koppeltaal interactions like: [Connecting to Koppeltaal](/technische-howto/connectie-maken-met-koppeltaal), [Launching](/technische-howto/launchen), [CRUD operations](/technische-howto/resources-managen/crud-operaties) and [Subscribing to changes](/technische-howto/resources-managen/abonneren-op-changes).

## What Koppeltaal server does it use?

{% hint style="warning" %}
It is not allowed to use the Koppeltaal Test Tooling on Itzos acc22 and production. Requests here should not be allowed.
{% endhint %}

The Test Tooling is a multitenant solution that allows you to work against multiple Koppeltaal servers (like the POC and Itzos acc21). You can configure your own clients.

## How to get started?

Navigate to the [Koppeltaal Test Tooling](https://testsuite.koppeltaal.headease.nl) and try it out. Everyone can register. It also allows you to work together with your colleagues by sharing SMART clients. Follow this video on how to set up your first Koppeltaal client:

{% hint style="info" %}
The video below is based on an old version of the test suite. It also supports:

1. Share SMART Clients with colleagues
2. Launch **to** the test suite
3. Launch as a `RelatedPerson`.
   {% endhint %}

{% embed url="<https://drive.google.com/file/d/1MunGICaVhni3xPjK3Z1oY21FZJ1L3d65/view>" %}


# Request Koppeltaal server metadata

Koppeltaal metadata resides at two places

### CapabilityStatement

The Koppeltaal Server provides a [`CapabilityStatement`](https://www.hl7.org/fhir/r4/capabilitystatement.html). This statement contains useful metadata related to the Koppeltaal Server. For example, it indicates the supported Resource types and supported MIME types.

### SMART on FHIR Conformance

Koppeltaal also makes use of the [SMART on FHIR conformance](https://build.fhir.org/ig/HL7/smart-app-launch/conformance.html#conformance). This specifically contains metadata used whilst executing the [SMART on FHIR specifications](https://smarthealthit.org/). This conformance can be found `<BASE_FHIR_URL>/.well-known/smart-configuration`. This way, there is no need to configure hard-coded URLs. This configuration can be used to, for example, retrieve the Auth Server URL for the specific Koppeltaal server at runtime.

## Topics

[TOP-KT-016 - SMART on FHIR Conformiteit](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27108972/TOP-KT-016+-+SMART+on+FHIR+Conformiteit)


# Connecting to Koppeltaal

To interact with the Koppeltaal server, applications must authenticate via the [SMART Backend Service specification](https://hl7.org/fhir/smart-app-launch/backend-services.html). The necessary steps are explained step by step in the following pages.


# Requirements

An `access_token` is required to access the Koppeltaal server. For this, the following steps must be performed:

1. The application possesses a [key pair](/technische-howto/connectie-maken-met-koppeltaal/requirements/key-pair-maken) and can sign [JWTs](/technische-howto/connectie-maken-met-koppeltaal/requirements/jwt-ondertekenen).
2. The application has a [JWKS endpoint](/technische-howto/connectie-maken-met-koppeltaal/requirements/jwks-opzetten).
3. The application has [joined the domain](/domain-access/domein-toetreden) with the JWKS endpoint set up and possesses a `client_id`.
4. The application has a [role](/domain-access/rollen-beheren) and the status "Active".


# Create a key pair

To retrieve data from the Koppeltaal server, an `access_token` must be retrieved. How this is done will be explained later. For now, it is important to know is that this works with a [JWT](https://jwt.io/) message. The JWT must be signed using an asymmetric key pair.

This [Docker image](https://github.com/Koppeltaal/Koppeltaal-2.0-Generate-KeyPair) can be used to generate an RSA key pair that works within the POC setup. The script generates an RSA key pair with a key length of 2048 bits and a `PKCS8` key format.

{% hint style="info" %}
For proper connection to the POC applications, we recommend the use of an RSA key pair.
{% endhint %}

The key is generated using the following commands:

```bash
ssh-keygen -t rsa -m PKCS8 -b 2048 -f private.key
openssl rsa -in private.key -pubout -outform PEM -out public.key

printf "Private key:\n\n"
cat private.key
printf "\nPublic key:\n\n"
cat public.key
printf "\n"
```


# Signing the JWT

Koppeltaal uses JWTs in several places. For the dev guide, two places are good to know about:

1. For [retrieving an access token](/technische-howto/connectie-maken-met-koppeltaal/toegang-tot-koppeltaal) that provides access to the Koppeltaal server.
2. For performing a [Koppeltaal launch](/technische-howto/launchen) using [HTI](https://github.com/GIDSOpenStandaarden/GIDS-HTI-Protocol/blob/master/HTI.md) or [SMART HTI](/technische-howto/launchen/smart-hti-on-fhir).

### What is a JWT?

JWT stands for JSON Web Token. A practical explanation of how a JWT works can be found [here](https://jwt.io/introduction). An important piece is:

> In its compact form, JSON Web Tokens consist of three parts separated by dots (`.`), which are:
>
> * Header
> * Payload
> * Signature
>
> Therefore, a JWT typically looks like the following.
>
> `xxxxx.yyyyy.zzzzz`

### Signing

The signing of the JWT takes place in the third part of the JWT: the signature (`zzzzz` in the example above). Koppeltaal uses asymmetric key pairs to sign the JWTs. The signature part is encrypted using the private key of the asymmetric key pair. The public-key part is published at the [JWKS](/technische-howto/connectie-maken-met-koppeltaal/requirements/jwks-opzetten) endpoint. This proves that a JWT is signed by a party in possession of the private-key. Signing the JWT is most easily performed using a JWT library for the relevant programming language.

{% hint style="info" %}
The [JWT debugger](https://jwt.io/?debug) is a great place to see, at runtime, what the contents of the JWT are and what the token looks like. Note that we work with key pairs and not shared secrets. So make sure to select algorithms that work with key pairs like `RS` and `ES`.
{% endhint %}

{% hint style="info" %}
RSA is more complicated to implement than, say, HMAC algorithms. However, it is a lot more secure. For example, there is no shared secret. Also, using JWKS, it is possible to quickly rotate keys.
{% endhint %}

## Topics

[TOP-KT-005c - Applicatie toegang: SMART on FHIR backend services](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27125356/TOP-KT-005c+-+Applicatie+toegang+SMART+on+FHIR+backend+services)


# JWKS setup

To securely validate a signed JWT, it is recommended to use [JSON Web Key Set (JWKS)](https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-key-sets).

The application must ensure that the generated key pair is translated into [JSON Web Key (JWK)](https://datatracker.ietf.org/doc/html/rfc7517) format. One or more JWK objects are then offered under a JWKS endpoint: `https://YOUR_DOMAIN/path-to/jwks.json`.

Because the public keys are now available under a fixed URL, a key can be revoked or rotated with ease.

{% hint style="info" %}
A lot of programming languages have libraries available to simply (semi)automatically offer an RSA key in PEM format as a JWKS endpoint. Look carefully at what is available before implementing this yourself!
{% endhint %}

{% hint style="info" %}
The use of a fixed path such as `https://YOUR_DOMAIN/.well-known/jwks.json` is discouraged to make hostile domain takeovers more complicated.
{% endhint %}

## Topics

[TOP-KT-020 - Uitwisseling publieke sleutels](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27126636/TOP-KT-020+-+Uitwisseling+publieke+sleutels)


# Access to Koppeltaal

## Request Flow

{% hint style="info" %}
For an interactive demo, go to our [Koppeltaal Test Tooling](https://testsuite.koppeltaal.headease.nl/).&#x20;
{% endhint %}

Koppeltaal requires that applications use the [SMART Backend Services: Authorization](https://hl7.org/fhir/uv/bulkdata/authorization/index.html#obtaining-an-access-token) flow to request an `access_token`. The following diagram is used for this purpose

![SMART Backend auth flow](https://1577345028-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiVMn-5GzUw-bGYHPT8%2Fuploads%2Fgit-blob-9b46ca7834a1f7343f928e098887e72815aea480%2Fbackend-service-authorization-diagram.png?alt=media)

{% hint style="info" %}
The contents of the JWT and the OAuth request are described in detail [here](https://hl7.org/fhir/uv/bulkdata/authorization/index.html#protocol-details). Koppeltaal has an exception to the `scope` parameter. It may be sent by the client, but its value is set by the auth server based on the client's role.
{% endhint %}

{% hint style="warning" %}
The FHIR documentation mentions multiple `alg` header values (e.g., RS384, ES384). Within the POC environment, we only support RS512.
{% endhint %}

### 1. JWT creation

The above diagram shows that a JWT token is first compiled and [signed](/technische-howto/connectie-maken-met-koppeltaal/requirements/jwt-ondertekenen). The following fields must be set:

| Field | Value                                                                                                                                                                                                                                                                                                              |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| iss   | Fill with the `client_id` value provided while [Joining a domain](/domain-access/domein-toetreden)                                                                                                                                                                                                                 |
| sub   | Fill with the `client_id` value provided while [Joining a domain](/domain-access/domein-toetreden)                                                                                                                                                                                                                 |
| exp   | UNIX timestamp of now + 5 minutes                                                                                                                                                                                                                                                                                  |
| aud   | <p>Fill with <a href="https://auth-service.koppeltaal.headease.nl/oauth2/token"><https://auth-service.koppeltaal.headease.nl/oauth2/token></a></p><p>(value can be extracted from the <a href="/technische-howto/koppeltaal-server-metadata-opvragen#smart-on-fhir-conformance">SMART on FHIR conformance</a>)</p> |
| jti   | Random identifier, this is used by the auth server to prevent replay attacks. Use something like a GUID here.                                                                                                                                                                                                      |

### 2. Access Token Request

Execute the following request:

## Request access\_token

<mark style="color:green;">`POST`</mark> `https://auth-service.koppeltaal.headease.nl/oauth2/token`

See the Response tab for an example response.

#### Headers

| Name                                           | Type   | Description                         |
| ---------------------------------------------- | ------ | ----------------------------------- |
| Content-Type<mark style="color:red;">\*</mark> | string | `application/x-www-form-urlencoded` |

#### Request Body

| Name                                                      | Type   | Description                                                                                                          |
| --------------------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------- |
| client\_assertion<mark style="color:red;">\*</mark>       | string | The signed JWT                                                                                                       |
| client\_assertion\_type<mark style="color:red;">\*</mark> | string | <p>Always fill with</p><p><code>urn:ietf:params:oauth:client-assertion-type:jwt-bearer</code></p>                    |
| grant\_type<mark style="color:red;">\*</mark>             | string | <p>Always fill with</p><p><code>client\_credentials</code></p>                                                       |
| scope<mark style="color:red;">\*</mark>                   | string | <p>Content can be empty. The</p><p><code>scope</code></p><p>is set by the auth server based on the client's role</p> |

{% tabs %}
{% tab title="200" %}

```javascript
{
  "access_token": "eyJraWQiOiJKR3pTYmgzVS1TQlVabllIQjJQaWhzN0FBc0Vubk8zelpqUS1RSjFTN0tzIiwiYWxnIjoiUlM1MTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLXNlcnZpY2Uua29wcGVsdGFhbC5oZWFkZWFzZS5ubC8iLCJhdWQiOiJmaGlyLXNlcnZlciIsIm5iZiI6MTYzMTE5NDM0MCwiZXhwIjoxNjMxMTk3OTQwLCJub25jZSI6IjQ4NTI5NTc2LTFiZTctNGNmOS04MWM0LWRkMTVhMjE4NjcwNyIsInR5cGUiOiJhY2Nlc3MiLCJzY29wZSI6IiIsImF6cCI6IjVhZDdjZjZhLTk1NTYtNGQyMy05MWNhLTI1MGRhZmExZGYwOSJ9.cgBzTRhbvLFPug9bqvCtaVi9ogHpMDqqemoTJjA1C3OpMsU42VyrnNUZ41qtcsZfqjI5OspT678MyVhDHq6DDRc9GLbg8RFLjrow17PfBCgkFALCKXWi9r6gTOZdaGdEPKfqavn1r8-S2HnIaWdEVfNPA1ZlBBxkJsYLl-8zgPmykZDNCbIH1e_SevGc56GeF5dPjHzxSiAI2_t19FM0OL3JfLZ-T8DR5tcOo7xfDYD086AUUr0hQIkzbrhuLGHSM5X6QcX84IfZlC0jQ6v_YbdMXlMBDZfUZN1nbsjxtDRwiz0IzZtIOF1XXpS1j0rKy517Vu_cc6LOS1OasUAAEw",
  "expires_in": 3600,
  "token_type": "Bearer"
}
```

{% endtab %}

{% tab title="400" %}
The request has been submitted incorrectly. Probably due to missing parameters or the body is delivered in the wrong way.
{% endtab %}
{% endtabs %}

As shown above in the 200 Response, the `access_token` is passed as part of the response. This `access_token` must be passed along as a `Bearer` token in the [`Authorization` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) on every request to the Koppeltaal server. The format of the header is as follows:

```
Authorization: <type> <credentials>
```

In the example response, the header should look like this:

```
Authorization: Bearer T8DR5tcOo7xfDYD086AUUr0hQIkzbrhuLGHSM5X6QcX84IfZlC0jQ6v_YbdMXlMBDZfUZN1nbsjxtDRwiz0IzZtIOF1XXpS1j0rKy517Vu_cc6LOS1OasUAAEw
```

### Refreshing the access\_token

The `access_token` has a relatively short lifetime. When the token expires, the Koppeltaal server will return a `401` error. The [SMART Backend Services: Authorization](https://hl7.org/fhir/uv/bulkdata/authorization/index.html#obtaining-an-access-token) does not support a `refresh_token`. The application needs to redo steps 1 & 2.

## Topics

[TOP-KT-005c - Applicatie toegang: SMART on FHIR backend services](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27125356/TOP-KT-005c+-+Applicatie+toegang+SMART+on+FHIR+backend+services)


# Managing resources

It is very important to understand that **applications** connect to the Koppeltaal Server, and not the **end users**. Koppeltaal ensures that applications are only allowed to perform operations on resources to which they are authorised. At the user level, the applications themselves are responsible for keeping track of which operations are allowed to be performed.

So this means, for example, that an application may request all tasks to which they are authorised. However, the Koppeltaal Server does not know to whom this resource is shown (after all, it is provided to an application). So it is up to the application to ensure that the tasks of e.g. `Patient/123` are only shown to authorised users.


# Versioning

The Koppeltaal server keeps track of all versions of resources. Thus, all versions of a `Resource` can be [retrieved](/technische-howto/resources-managen/crud-operaties/resource-ophalen#specifieke-versie-van-een-resource-ophalen). The Koppeltaal server also enforces that changes to a `Resource` are based on the [latest version](/technische-howto/resources-managen/crud-operaties/resource-updaten#concurrency).

### Topics

[TOP-KT-002a - FHIR Resource Service interacties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27125763/TOP-KT-002a+-+FHIR+Resource+Service+interacties)


# CRUD Operations

{% hint style="info" %}
A complete overview of the RESTful API can be found [here](https://www.hl7.org/fhir/http.html).
{% endhint %}

Primary overview of useful RESTful calls and advice on which calls to use.

In order to quickly test against the FHIR service, the [OpenAPI specifications](https://fhir-server.koppeltaal.headease.nl/fhir/api-docs) can be used. For example to create all requests with parameters in Postman.


# Retrieve all Resources

Request all resources for a specific Resource-type

{% hint style="info" %}
See the [FHIR documentation](https://www.hl7.org/fhir/r4/http.html#read) for more information
{% endhint %}

{% hint style="info" %}
Returned results can be filtered by [Search Narrowing](/domain-access/rollen-beheren/search-narrowing).
{% endhint %}

## Retrieve all Resources

<mark style="color:blue;">`GET`</mark> `https://fhir-server.koppeltaal.headease.nl/fhir/DEFAULT/<Resource>`

Get ALL for type .

#### Path Parameters

| Name                                       | Type   | Description                    |
| ------------------------------------------ | ------ | ------------------------------ |
| Resource<mark style="color:red;">\*</mark> | string | Resource-type (e.g. `Patient`) |

#### Headers

<table><thead><tr><th>Name</th><th width="236">Type</th><th>Description</th></tr></thead><tbody><tr><td>Authentication<mark style="color:red;">*</mark></td><td>string</td><td><p>Bearer token obtained from the Auth Server</p><p></p><p>(zie <a href="/technische-howto/connectie-maken-met-koppeltaal">Connecting to Koppeltaal</a>)</p></td></tr></tbody></table>

{% tabs %}
{% tab title="200" %}

```json
{
  "resourceType": "Bundle",
  "id": "f0cfec85-0d26-44f9-a222-a478451d4bf9",
  "meta": {
    "lastUpdated": "2023-02-07T08:16:54.158+00:00"
  },
  "type": "searchset",
  "link": [
    {
      "relation": "self",
      "url": "https://fhir-server.koppeltaal.headease.nl/fhir/DEFAULT/Patient"
    },
    {
      "relation": "next",
      "url": "https://fhir-server.koppeltaal.headease.nl/fhir/DEFAULT?_getpages=f0cfec85-0d26-44f9-a222-a478451d4bf9&_getpagesoffset=40&_count=40&_pretty=true&_bundletype=searchset"
    }
  ],
  "entry": [
    {
      "fullUrl": "https://fhir-server.koppeltaal.headease.nl/fhir/DEFAULT/Patient/13befac2-de72-4926-99e8-24d0adb1fd62",
      "resource": {
        "resourceType": "Patient",
        "id": "13befac2-de72-4926-99e8-24d0adb1fd62",
        ...
      },
      "search": {
        "mode": "match"
      }
    },
    {
      "fullUrl": "https://fhir-server.koppeltaal.headease.nl/fhir/DEFAULT/Patient/d20b53b0-5b35-493c-9cbd-40673d5ce22e",
      "resource": {
        "resourceType": "Patient",
        "id": "d20b53b0-5b35-493c-9cbd-40673d5ce22e",
        ...
      },
      "search": {
        "mode": "match"
      }
    }
  ]
}

```

{% endtab %}

{% tab title="401" %}
Unauthenticated
{% endtab %}

{% tab title="403" %}
Unauthorized
{% endtab %}
{% endtabs %}

## Topics

[TOP-KT-002a - FHIR Resource Service interacties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27125763/TOP-KT-002a+-+FHIR+Resource+Service+interacties)

[TOP-KT-005a - Rollen en rechten voor applicatie-instanties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123707/TOP-KT-005a+-+Rollen+en+rechten+voor+applicatie-instanties)

[TOP-KT-009 - Overzicht gebruikte FHIR Resources](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27071328/TOP-KT-009+-+Overzicht+gebruikte+FHIR+Resources)


# Retrieve specific Resource

Request a specific instance of a Resource

{% hint style="info" %}
See the [FHIR documentation](https://www.hl7.org/fhir/r4/http.html#read) for more information.
{% endhint %}

## Retrieve specific Resource

<mark style="color:blue;">`GET`</mark> `https://hapi-fhir-server.koppeltaal.headease.nl/fhir/<Resource>/<:id>`

#### Path Parameters

| Name                                 | Type   | Description                 |
| ------------------------------------ | ------ | --------------------------- |
| id<mark style="color:red;">\*</mark> | string | Resource.id to be retrieved |

#### Headers

| Name                                             | Type   | Description                                                                                                                                                  |
| ------------------------------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Authentication<mark style="color:red;">\*</mark> | string | <p>Bearer token obtained from the Auth Server (see</p><p><a href="/technische-howto/connectie-maken-met-koppeltaal">Connecting to Koppeltaal</a></p><p>)</p> |

{% tabs %}
{% tab title="200 " %}

```json
{
    "resourceType": "Patient",
    "id": "13befac2-de72-4926-99e8-24d0adb1fd62",
    "meta": {
        "versionId": "1",
        "lastUpdated": "2023-01-17T08:52:04.997+00:00",
        "source": "urn:uuid:c712f204-abe7-4ec1-bad0-6dc3dfa1afd8#26be13a5038c6a77",
        "profile": [
            "http://koppeltaal.nl/fhir/StructureDefinition/KT2Patient"
        ]
    },
    "text": {
        "status": "generated",
        "div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\">null <b>SUITE </b></div><table class=\"hapiPropertyTable\"><tbody><tr><td>Identifier</td><td>6cc2bea5</td></tr><tr><td>Date of birth</td><td><span>17 January 2023</span></td></tr></tbody></table></div>"
    },
    "extension": [
        {
            "url": "http://koppeltaal.nl/fhir/StructureDefinition/resource-origin",
            "valueReference": {
                "reference": "Device/9f3ac641-bf1a-4f62-82b2-9825f80e6847",
                "type": "Device"
            }
        }
    ],
    "identifier": [
        {
            "system": "https://koppeltaal.nl/identifier/TestSuiteIdentifier",
            "value": "6cc2bea5"
        }
    ],
    "active": true,
    "name": [
        {
            "use": "official",
            "family": "Suite",
            "given": [
                null
            ],
            "_given": [
                {
                    "extension": [
                        {
                            "url": "http://hl7.org/fhir/StructureDefinition/iso21090-EN-qualifier",
                            "valueCode": "IN"
                        }
                    ]
                }
            ]
        }
    ],
    "gender": "male",
    "birthDate": "2023-01-17"
}
```

{% endtab %}

{% tab title="401" %}
Unauthenticated
{% endtab %}

{% tab title="403" %}
Unauthorized
{% endtab %}

{% tab title="404" %}

```
Not Found Resource with id does not exist
```

{% endtab %}

{% tab title="410" %}

```
Gone Resource has been deleted
```

{% endtab %}
{% endtabs %}

## Retrieve specific version of a Resource (vread)&#x20;

<mark style="color:blue;">`GET`</mark> `https://hapi-fhir-server.koppeltaal.headease.nl/fhir/<Resource>/<:id>/_history/<:versie>`

#### Path Parameters

| Name                                     | Type    | Description                 |
| ---------------------------------------- | ------- | --------------------------- |
| id<mark style="color:red;">\*</mark>     | String  | Resource.id to be retrieved |
| versie<mark style="color:red;">\*</mark> | Integer | The version                 |

#### Headers

<table><thead><tr><th>Name</th><th width="221">Type</th><th>Description</th></tr></thead><tbody><tr><td>Authorization<mark style="color:red;">*</mark></td><td>String</td><td><p>Bearer token verkregen via de Auth Server</p><p></p><p>(zie <a href="/technische-howto/connectie-maken-met-koppeltaal">Connecting to Koppeltaal</a> )</p></td></tr></tbody></table>

{% tabs %}
{% tab title="200" %}

```json
{
    "resourceType": "Patient",
    "id": "13befac2-de72-4926-99e8-24d0adb1fd62",
    "meta": {
        "versionId": "1",
        "lastUpdated": "2023-01-17T08:52:04.997+00:00",
        "source": "urn:uuid:c712f204-abe7-4ec1-bad0-6dc3dfa1afd8#26be13a5038c6a77",
        "profile": [
            "http://koppeltaal.nl/fhir/StructureDefinition/KT2Patient"
        ]
    },
    "text": {
        "status": "generated",
        "div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"hapiHeaderText\">null <b>SUITE </b></div><table class=\"hapiPropertyTable\"><tbody><tr><td>Identifier</td><td>6cc2bea5</td></tr><tr><td>Date of birth</td><td><span>17 January 2023</span></td></tr></tbody></table></div>"
    },
    "extension": [
        {
            "url": "http://koppeltaal.nl/fhir/StructureDefinition/resource-origin",
            "valueReference": {
                "reference": "Device/9f3ac641-bf1a-4f62-82b2-9825f80e6847",
                "type": "Device"
            }
        }
    ],
    "identifier": [
        {
            "system": "https://koppeltaal.nl/identifier/TestSuiteIdentifier",
            "value": "6cc2bea5"
        }
    ],
    "active": true,
    "name": [
        {
            "use": "official",
            "family": "Suite",
            "given": [
                null
            ],
            "_given": [
                {
                    "extension": [
                        {
                            "url": "http://hl7.org/fhir/StructureDefinition/iso21090-EN-qualifier",
                            "valueCode": "IN"
                        }
                    ]
                }
            ]
        }
    ],
    "gender": "male",
    "birthDate": "2023-01-17"
}
```

{% endtab %}

{% tab title="401" %}
Unauthenticated
{% endtab %}

{% tab title="403" %}
Unauthorized
{% endtab %}

{% tab title="404" %}
Resource with id does not exist
{% endtab %}

{% tab title="410 " %}
Gone Resource has been deleted
{% endtab %}
{% endtabs %}

## Topics

[TOP-KT-002a - FHIR Resource Service interacties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27125763/TOP-KT-002a+-+FHIR+Resource+Service+interacties)

[TOP-KT-003 - Logische ID, bedrijfsidentifier, referenties en referentie integriteit](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27066395/TOP-KT-003+-+Logische+ID+bedrijfsidentifier+referenties+en+referentie+integriteit)

[TOP-KT-005a - Rollen en rechten voor applicatie-instanties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123707/TOP-KT-005a+-+Rollen+en+rechten+voor+applicatie-instanties)

[TOP-KT-009 - Overzicht gebruikte FHIR Resources](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27071328/TOP-KT-009+-+Overzicht+gebruikte+FHIR+Resources)


# Create a Resource

{% hint style="info" %}
See the [FHIR documentation](https://www.hl7.org/fhir/r4/http.html#create) for more information.
{% endhint %}

### Business identifiers

Koppeltaal enforces setting business identifiers on `Resources` by making the `identifier` field mandatory. The main reason for this is so that a source system can consistently keep track of whether a Koppeltaal variant of their entity already exists. In addition, business identifiers can help when there are multiple source systems that need to know if a `Resource` already exists.

### Koppeltaal Profiles

The Koppeltaal server validates all `Resources` being created or updated. The server enforces that resources are sent in compliance with the [Koppeltaal profiles](https://simplifier.net/Koppeltaalv2.0/~resources?category=Profile\&fhirVersion=R4\&sortBy=RankScore_desc). Profiles are stored in FHIR as [`StructureDefinition`](https://www.hl7.org/FHIR/r4/structuredefinition.html) resources. To indicate that a resource has been created in compliance with a profile, the `Resource.meta.profiles` array must be filled. The value should always be filled with the canonical identifier of the profile. This can be found in [simplifier](https://simplifier.net/Koppeltaalv2.0/~resources?category=Profile\&fhirVersion=R4\&sortBy=RankScore_desc):

![Canonical identifier ophalen bij simplifier.net](https://1577345028-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiVMn-5GzUw-bGYHPT8%2Fuploads%2Fgit-blob-8895bb705b19663de71ed4bdaadd1704c810ffce%2FScreenshot%202021-12-09%20at%2010.42.16.png?alt=media)

For example:

```json
{
  "resourceType": "Subscription",
  "meta": {
    "profile": [
      "http://koppeltaal.nl/fhir/StructureDefinition/KT2Subscription"
    ]
  }
  ...
  }
}
```

### Conditional Create

{% hint style="warning" %}
The conditional create is still in the "trial use" phase. Thus, the status of this functionality has yet to be reviewed.
{% endhint %}

The FHIR specification describes [conditional creates](https://www.hl7.org/fhir/r4/http.html#ccreate). When a `Resource` is created, an `upsert` can be performed based on the business identifier. When multiple applications in a domain create the same type of `Resources`, it is important that there is clear agreement on which identifier system is used. The conditional create helps prevent duplicate resources being created at Koppeltaal.

## Conditional Create Request

<mark style="color:green;">`POST`</mark> `https://fhir-server.koppeltaal.headease.nl/fhir/DEFAULT/<Resource>`

#### Headers

<table><thead><tr><th>Name</th><th width="225">Type</th><th>Description</th></tr></thead><tbody><tr><td>Content-Type<mark style="color:red;">*</mark></td><td>String</td><td><p><code>application/fhir+json</code></p><p>OR</p><p><code>application/fhir+xml</code></p></td></tr><tr><td>If-None-Exist<mark style="color:red;">*</mark></td><td>string</td><td><p>The business identifier, e.g:</p><p><code>identifier=http://my-lab-system|123</code></p></td></tr><tr><td>Authorization<mark style="color:red;">*</mark></td><td>string</td><td><p>Bearer token obtained from the Auth Server</p><p></p><p>(see <a href="/technische-howto/connectie-maken-met-koppeltaal">Connecting to Koppeltaal</a>)</p></td></tr></tbody></table>

#### Request Body

| Name                               | Type   | Description |
| ---------------------------------- | ------ | ----------- |
| <mark style="color:red;">\*</mark> | object | Resource    |

{% tabs %}
{% tab title="200 " %}
The resource already existed. The POST was not processed.
{% endtab %}

{% tab title="201 " %}
Resource is created. The resource with resource-origin extension and id is returned.
{% endtab %}

{% tab title="400" %}
The resource cannot be parsed or does not conform to the basic FHIR validation rules
{% endtab %}

{% tab title="401" %}
Unauthenticated
{% endtab %}

{% tab title="403" %}
Unauthorized
{% endtab %}

{% tab title="404" %}
Resource type is not supported
{% endtab %}

{% tab title="412" %}
More than one match found. The If-None-Exist is not selective enough.
{% endtab %}

{% tab title="422" %}
Does not meet FHIR profiles or Koppeltaal business rules
{% endtab %}
{% endtabs %}

## Create Request

<mark style="color:green;">`POST`</mark> `https://fhir-server.koppeltaal.headease.nl/fhir/DEFAULT/<Resource>`

#### Headers

| Name                                            | Type   | Description                                                                                                                                                                |
| ----------------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Content-type<mark style="color:red;">\*</mark>  | String | <p><code>application/fhir+json</code></p><p>OR</p><p><code>application/fhir+xml</code></p>                                                                                 |
| Authorization<mark style="color:red;">\*</mark> | string | <p>Bearer token obtained from the Auth Server</p><p>\</p><p>(see</p><p><a href="/technische-howto/connectie-maken-met-koppeltaal">Connecting to Koppeltaal</a></p><p>)</p> |

#### Request Body

| Name                               | Type   | Description |
| ---------------------------------- | ------ | ----------- |
| <mark style="color:red;">\*</mark> | object | Resource    |

{% tabs %}
{% tab title="201" %}
Resource is created. The resource with resource-origin extension and id is returned.
{% endtab %}

{% tab title="400" %}
The resource cannot be parsed or does not conform to the basic FHIR validation rules
{% endtab %}

{% tab title="401" %}
Unauthenticated
{% endtab %}

{% tab title="403" %}
Unauthorized
{% endtab %}

{% tab title="404" %}
Resource type is not supported
{% endtab %}

{% tab title="422" %}
Does not meet FHIR profiles or Koppeltaal business rules
{% endtab %}
{% endtabs %}

## Topics

[TOP-KT-002a - FHIR Resource Service interacties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27125763/TOP-KT-002a+-+FHIR+Resource+Service+interacties)

[TOP-KT-005a - Rollen en rechten voor applicatie-instanties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123707/TOP-KT-005a+-+Rollen+en+rechten+voor+applicatie-instanties)

[TOP-KT-009 - Overzicht gebruikte FHIR Resources](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27071328/TOP-KT-009+-+Overzicht+gebruikte+FHIR+Resources)


# Update a Resource

{% hint style="info" %}
See the [FHIR documentation](https://www.hl7.org/fhir/r4/http.html#update) for more information.
{% endhint %}

### Concurrency

To avoid overwriting data, an application must always indicate which version of a `Resource` the update is based on. This is done using the `If-Match` header. If this header is missing, the Koppeltaal server will reject the request. If the update is not based on the latest version, the server will respond with a `409 Conflict` or a `412 Precondition Failed`.

The `If-Match` value must match the latest `ETag` value. The `ETag` value is provided via a response header sent by the Koppeltaal server after a [`Create`](/technische-howto/resources-managen/crud-operaties/resource-aanmaken), [`Update`](/technische-howto/resources-managen/crud-operaties/resource-updaten) or [`Get`](/technische-howto/resources-managen/crud-operaties/resource-ophalen#retrieve-specific-resource).

## Update a complete resource

<mark style="color:orange;">`PUT`</mark> `https://fhir-server.koppeltaal.headease.nl/fhir/DEFAULT/<Resource>/<:id>`

Note: the

`id`

property has to be set in the body as well

#### Path Parameters

| Name                                 | Type   | Description                                                |
| ------------------------------------ | ------ | ---------------------------------------------------------- |
| id<mark style="color:red;">\*</mark> | string | <p>The "logical id" of the</p><p><code>Resource</code></p> |

#### Headers

<table><thead><tr><th>Name</th><th width="217">Type</th><th>Description</th></tr></thead><tbody><tr><td>If-Match<mark style="color:red;">*</mark></td><td>string</td><td><p>A</p><p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Match">"weak" ETag</a></p><p>to the version the update is based on, e.g: W/"3"</p></td></tr><tr><td>Authorization<mark style="color:red;">*</mark></td><td>string</td><td><p>Bearer token obtained from the Auth Server</p><p></p><p>(see <a href="/technische-howto/connectie-maken-met-koppeltaal">Connecting to Koppeltaal</a>)</p></td></tr></tbody></table>

#### Request Body

| Name                               | Type   | Description                            |
| ---------------------------------- | ------ | -------------------------------------- |
| <mark style="color:red;">\*</mark> | string | <p>The</p><p><code>Resource</code></p> |

{% tabs %}
{% tab title="200" %}
Resource is modified. The resource with resource-origin extension and logical id is returned
{% endtab %}

{% tab title="400" %}
The resource cannot be parsed or does not conform to the basic FHIR validation rules
{% endtab %}

{% tab title="401" %}
Unauthenticated
{% endtab %}

{% tab title="403" %}
Unauthorized
{% endtab %}

{% tab title="404" %}
Resource type not supported, or not a FHIR end-point
{% endtab %}

{% tab title="405" %}
The Resource did not exist prior to the update, and the server does not allow client defined ids
{% endtab %}

{% tab title="409" %}
Version conflict, update is based on an old version
{% endtab %}

{% tab title="412" %}
Precondition Failed Version conflict, update is based on an old version
{% endtab %}

{% tab title="422" %}
Does not meet FHIR profiles or Koppeltaal business rules
{% endtab %}
{% endtabs %}

### Delen van een Resource Updaten

{% hint style="warning" %}
PATCH requests are optional. See the [`Conformance`](/technische-howto/koppeltaal-server-metadata-opvragen#capabilitystatement) to find out if the server supports this.
{% endhint %}

To update a `Resource` via a small payload, the Koppeltaal server may support `PATCH` requests. The payload of the `PATCH` must be one of the following:

1. A [JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902) (Content-Type application/json-patch+json).
2. An [XML Patch](https://datatracker.ietf.org/doc/html/rfc5261) (Content-Type application/xml-patch+xml)
3. A [FHIRPath Patch](https://www.hl7.org/fhir/r4/fhirpatch.html) parameters Resource (Content-Type [FHIR Content Type](https://www.hl7.org/fhir/r4/http.html#mime-type)).

This is what the payload looks like from a JSON Patch to update the status of a `Task`

```
[{
    "op": "replace",
    "path": "/status",
    "value": "completed"
}]
```

More examples of patches can be downloaded [here](https://www.hl7.org/fhir/r4/test-cases.zip).

## Patch a Resource

<mark style="color:purple;">`PATCH`</mark> `https://hapi-fhir-server.koppeltaal.headease.nl/fhir/<Resource>/<:id>`

As an alternative to updating an entire resource, clients can perform a patch operation. This can be useful when a client is seeking to minimize its bandwidth utilization.

#### Path Parameters

| Name                               | Type   | Description                                                |
| ---------------------------------- | ------ | ---------------------------------------------------------- |
| <mark style="color:red;">\*</mark> | String | <p>The "logical id" of the</p><p><code>Resource</code></p> |

#### Headers

<table><thead><tr><th>Name</th><th width="211">Type</th><th>Description</th></tr></thead><tbody><tr><td>If-Match<mark style="color:red;">*</mark></td><td>string</td><td><p>A</p><p><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Match">"weak" ETag</a></p><p>to the version the update is based on, e.g: W/"3"</p></td></tr><tr><td>Authorization<mark style="color:red;">*</mark></td><td>string</td><td><p>Bearer token obtained from the Auth Server</p><p></p><p>(see <a href="/technische-howto/connectie-maken-met-koppeltaal">Connecting to Koppeltaal</a>)</p></td></tr></tbody></table>

#### Request Body

| Name                               | Type   | Description |
| ---------------------------------- | ------ | ----------- |
| <mark style="color:red;">\*</mark> | object | The Patch   |

{% tabs %}
{% tab title="200" %}
Patch is applied. The complete Resource will be returned
{% endtab %}

{% tab title="401" %}
Unauthenticated
{% endtab %}

{% tab title="403" %}
Unauthorized
{% endtab %}

{% tab title="404" %}

```
Not Found Resource type not supported, or not a FHIR end-point
```

{% endtab %}

{% tab title="405" %}

```
Method Not Allowed 
```

{% endtab %}

{% tab title="412" %}

```
Precondition Failed Version conflict, update is based on an old version
```

{% endtab %}
{% endtabs %}

## Topics

[TOP-KT-002a - FHIR Resource Service interacties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27125763/TOP-KT-002a+-+FHIR+Resource+Service+interacties)

[TOP-KT-005a - Rollen en rechten voor applicatie-instanties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123707/TOP-KT-005a+-+Rollen+en+rechten+voor+applicatie-instanties)

[TOP-KT-009 - Overzicht gebruikte FHIR Resources](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27071328/TOP-KT-009+-+Overzicht+gebruikte+FHIR+Resources)


# Delete a Resource

### Do not use deletes

In Koppeltaal, we do not delete resources by default. As an alternative, we mark a resource as being end-of-life. This can be done with the following properties:

| `ActivityDefinition` | status | retired                                |
| -------------------- | ------ | -------------------------------------- |
| `Endpoint`           | status | off                                    |
| `Device`             | status | inactive                               |
| `Task`               | status | completed\|cancelled\|failed\|rejected |
| `Patient`            | active | false                                  |
| `Practitioner`       | active | false                                  |
| `RelatedPerson`      | active | false                                  |
| `CareTeam`           | status | inactive                               |
| `Subscription`       | status | off                                    |

### Logical deletes

{% hint style="info" %}
Keep in mind that the request below is normally NOT used. Please read the section above.
{% endhint %}

When an application does get the permission to execute a `DELETE` request, the resource will be marked as deleted. When a client requests this resource, the server will respond with a `410 Gone`. However, applications will still be allowed to request older versions via the [vread](/technische-howto/resources-managen/crud-operaties/resource-ophalen#retrieve-specific-version-of-a-resource-vread) request.

## Logical deletion of a specific resource instance

<mark style="color:red;">`DELETE`</mark> `https://fhir-server.koppeltaal.headease.nl/fhir/DEFAULT/<Resource>/<id>`

#### Path Parameters

| Name                                          | Type   | Description                                               |
| --------------------------------------------- | ------ | --------------------------------------------------------- |
| \<Resource><mark style="color:red;">\*</mark> | String | <p>The resource type, e.g:</p><p><code>Patient</code></p> |
| \<id><mark style="color:red;">\*</mark>       | String | The instance id                                           |

{% tabs %}
{% tab title="200" %}

```javascript
{
  "resourceType": "OperationOutcome",
  "text": {
    "status": "generated",
    "div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><h1>Operation Outcome</h1><table border=\"0\"><tr><td style=\"font-weight: bold;\">INFORMATION</td><td>[]</td><td>Successfully deleted 1 resource(s). Took 22ms.</td></tr></table></div>"
  },
  "issue": [
    {
      "severity": "information",
      "code": "informational",
      "details": {
        "coding": [
          {
            "system": "https://hapifhir.io/fhir/CodeSystem/hapi-fhir-storage-response-code",
            "code": "SUCCESSFUL_DELETE",
            "display": "Delete succeeded."
          }
        ]
      },
      "diagnostics": "Successfully deleted 1 resource(s). Took 22ms."
    }
  ]
}
```

{% endtab %}

{% tab title="204" %}

```javascript
No Content Delete successful, no OperationOutcome
```

{% endtab %}

{% tab title="401" %}
Unauthenticated
{% endtab %}

{% tab title="403" %}
Unauthorized
{% endtab %}

{% tab title="404" %}

```javascript
Resource not found
```

{% endtab %}
{% endtabs %}

### Right to be forgotten

In scenarios where users are able to use their right to be forgotten, the deletion of the data should always be done via the domain admin. Some solutions might require a manual delete, and certain solutions might support a `DELETE` request with the `$expunge` operator.

## Topics

[TOP-KT-002a - FHIR Resource Service interacties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27125763/TOP-KT-002a+-+FHIR+Resource+Service+interacties)

[TOP-KT-005a - Rollen en rechten voor applicatie-instanties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123707/TOP-KT-005a+-+Rollen+en+rechten+voor+applicatie-instanties)

[TOP-KT-009 - Overzicht gebruikte FHIR Resources](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27071328/TOP-KT-009+-+Overzicht+gebruikte+FHIR+Resources)


# Subscribing to changes

It is often important to be notified of changes to specific resources. Within Koppeltaal it is possible to be notified of changes on a very accurate level.

{% hint style="warning" %}
The notification mechanism has a maturity level 3. We know that FHIR is working hard to improve the notification mechanism. In the future version, it is very likely that this functionality will change. For example, currently there is no notification when a resource is deleted.
{% endhint %}

### Subscribe to changes

Applications can create their own notification using the [`Subscription`](https://www.hl7.org/fhir/r4/subscription.html) resource. This must adhere to the [Koppeltaal 2.0 profile](https://simplifier.net/koppeltaalv2.0/kt2subscription). The `Subscription`, like the other resources, can be managed through the [CRUD Operations](/technische-howto/resources-managen/crud-operaties).

#### Criteria

The `Subscription.criteria` field can be filled by applications themselves. With each change, the Koppeltaal server will check if there are `Subscriptions` where the criteria matches the created/changed `Resource`. If so, a `POST` notification will be sent to the `Subscription.channel.endpoint` for the matched subscriptions.

#### Koppeltaal-specific criteria

It's possible to subscribe to custom search criteria added by Koppeltaal. This is done by defining `SearchParameter` resources. Koppeltaal provides `SearchParameters` that are likely to be used. Information on these can be found on [Confluence](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27125775/TOP-KT-002b+-+Search+interacties).

#### Channel

The `Subscription.channel` is used to specify how and where the notification should go. In the POC, Koppeltaal will only support the `rest-hook` type without a payload.

{% hint style="info" %}
The Koppeltaal Server applies "Notification Narrowing"; similar to [Search Narrowing](/domain-access/rollen-beheren/search-narrowing) but for notifications. However, when something goes wrong in this process, the notification WILL be sent. In addition, an application may have multiple `Subscriptions` that match the set `criteria`.

Applications should therefore note that a notification does not always result in a`Resource` to be retrieved.

Applications should also note that subscriptions might not be received. Perhaps the webhook endpoint was unavailable, or the process runs into an error somewhere. When syncing state is important, it is important to keep the before-mentioned in mind and implement a mechanism that still synchronises all data.
{% endhint %}

### Limitations

There are differences between the FHIR `Subscription` and the Koppeltaal 2.0 profile. For example, Koppeltaal does not allow the creation of a `Subscription` where the `Subscription.payload` is turned on. This way, the notification is purely a "ping" to indicate that something has changed, but not WHAT content has changed. This choice was made to avoid accidentally sending sensitive information to the wrong endpoint.

### Example Subscription

```json
{
  "resourceType": "Subscription",
  "meta": {
    "profile": [
      "http://koppeltaal.nl/fhir/StructureDefinition/KT2Subscription"
    ]
  },
  "status": "active",
  "reason": "Process finished Tasks",
  "criteria": "Task?status=ready",
  "channel": {
    "type": "rest-hook",
    "endpoint": "https://koppeltaal-testteam6.nl/fictief-subscription",
    "header": [
      "X-KTSubscription: TaskReady",
      "Authorization: Bearer <TOKEN>"
    ]
  }
}
```

## Topics

[TOP-KT-005a - Rollen en rechten voor applicatie-instanties](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123707/TOP-KT-005a+-+Rollen+en+rechten+voor+applicatie-instanties)

[TOP-KT-006 - Abonneren op en signaleren van gebeurtenissen](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27084921/TOP-KT-006+-+Abonneren+op+en+signaleren+van+gebeurtenissen)

[TOP-KT-009 - Overzicht gebruikte FHIR Resources](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27071328/TOP-KT-009+-+Overzicht+gebruikte+FHIR+Resources)


# Launching

Koppeltaal supports two launch mechanisms: [HTI](/technische-howto/launchen/hti) and [SMART HTI On FHIR](/technische-howto/launchen/smart-hti-on-fhir). The latter is based on the [SMART App Launch](https://www.hl7.org/fhir/smart-app-launch/). There are slight differences, but where possible they are similar. Both mechanisms work at their core with the HTI JWT token, making both systems very similar in implementation. For sending out a launch, there are minimal differences. The receiving party (`module provider`) can, in the case of a SHOF launch, still choose to execute the HTI Flow.

{% hint style="info" %}
After reading the launch documentation, we recommend looking at the [Koppeltaal Test Tooling](/technische-howto/koppeltaal-test-tooling). This offers an interactive way of sending and/or receiving a launch.
{% endhint %}


# HTI Flow

Health Tools Interoperability

[HTI](https://github.com/GIDSOpenStandaarden/GIDS-HTI-Protocol/blob/master/HTI.md) is a light-weight solution from [GIDS](https://www.gidsopenstandaarden.org/hti-health-tools-interoperability) to quickly implement client-to-client launches. In short, the HTI launch is simply a [signed JWT](/technische-howto/connectie-maken-met-koppeltaal/requirements/jwt-ondertekenen) with HTI-specific claims that is sent from one client to another. A public key can be used to verify that the JWT comes from a trusted source.

### Requirements

1. A [JWKS endpoint must be available](/technische-howto/connectie-maken-met-koppeltaal/requirements/jwks-opzetten).
2. The `module provider` uses [Token Introspection](/technische-howto/launchen/launch-ontvangen/token-introspection) OR must be able to relate the issuer to its JWKS endpoint.

### Information Flow

The HTI launch can be done without an authentication server. Therefore, it is important that the `module provider` is in possession of the issuer and the related JWKS endpoint. This way it can be proven that the `portal` actually signed the JWT. A public key may also be exchanged, although there is a strong preference to use JWKS since applications must implement it to make a [Connection with Koppeltaal](/technische-howto/connectie-maken-met-koppeltaal).

<figure><img src="https://1577345028-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiVMn-5GzUw-bGYHPT8%2Fuploads%2Fgit-blob-5f4a71620947b2bb61205004564353ab0a0d75b7%2Fimage19.png?alt=media" alt="HTI Flow"><figcaption><p>HTI Flow</p></figcaption></figure>

## Topics

[TOP-KT-007 - Koppeltaal Launch](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123510/TOP-KT-007+-+Koppeltaal+Launch)

[TOP-KT-021 - Token Introspection](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27131284/TOP-KT-021+-+Token+Introspection)


# SHOF Flow

SMART HTI On FHIR

{% hint style="warning" %}
The Koppeltaal Server authorises applications, not users. This is a mismatch with the [SMART App Launch Framework](http://www.hl7.org/fhir/smart-app-launch/) (SALF). For example, the SALF flow always expects to return a user-level `access_token`. With SMART HTI On FHIR (SHOF), an `access_token` will also be returned, only this is a `no-op` token.
{% endhint %}

SMART HTI On FHIR (SHOF) uses the HTI token as the `launch` parameter value. This means that the launching party can reuse all logic during a launch. The main differences between HTI and SHOF are:

1. SHOF uses the `launch` parameter to pass the context as a HTI token, where HTI uses the `token` parameter to pass the context as a HTI token
2. SHOF is based on an international standard: [SMART App Launch Framework](http://www.hl7.org/fhir/smart-app-launch/).
3. SHOF performs an additional check on the logged-in user during the `/authorize` step, using a shared IdP. This prevents a launch token from being intercepted and executed. The user identifier contained in the launch token is compared to the identifier of the logged in user on the IdP.

### Requirements

1. A [JWKS endpoint must be available](/technische-howto/connectie-maken-met-koppeltaal/requirements/jwks-opzetten).
2. The user performing the launch must have an account on the shared IdP, the username has to be present on the corresponding user Resource (`Patient`, `Practitioner`, or `RelatedPerson`).

### Information Flow

<figure><img src="https://1577345028-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiVMn-5GzUw-bGYHPT8%2Fuploads%2Fgit-blob-00cbadc8ba749a6b30f2b8e3c3a3b8a5165b424c%2FSMART%20on%20FHIR%20app%20launch%20and%20HTI.drawio%20(1).png?alt=media" alt="SMART HTI Flow"><figcaption><p>SMART HTI Flow</p></figcaption></figure>

## Topics

[TOP-KT-007 - Koppeltaal Launch](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123510/TOP-KT-007+-+Koppeltaal+Launch)


# Compose a launch

The launch steps on this page are the same for HTI as SHOF

To perform the launch, the following steps must be performed for both HTI and SHOF:

### 1. Create Koppeltaal context claims

Koppeltaal supports the following claims:

<table><thead><tr><th width="124">HTI claim</th><th width="104">Type</th><th width="77">Required</th><th>Description</th></tr></thead><tbody><tr><td>resource</td><td>string</td><td>yes</td><td>The identifier of the task to be executed by the person in the <code>sub</code> field.</td></tr><tr><td>definition</td><td>url</td><td>no</td><td>A <code>Reference</code> that refers to the FHIR <code>ActivityDefinition</code>. The reference can be found on the <a href="https://simplifier.net/koppeltaalv2.0/instantiates"><code>Task.instantiates</code></a> extension.</td></tr><tr><td>sub</td><td>reference</td><td>yes</td><td>This is a <a href="https://github.com/GIDSOpenStandaarden/GIDS-HTI-Protocol/diffs/1?base_sha=0899d43a8ed3a53ccaf1ca3f1638753a28bdb7fb&#x26;branch=fhir-2-fields&#x26;commentable=true&#x26;name=fhir-2-fields&#x26;pull_number=23&#x26;qualified_name=refs%2Fheads%2Ffhir-2-fields&#x26;sha1=0899d43a8ed3a53ccaf1ca3f1638753a28bdb7fb&#x26;sha2=6f3ee98c1338f689c62e45a222d1e9e1d64142b8&#x26;short_path=baf3810&#x26;unchanged=expanded&#x26;w=false#person-reference">person reference</a> to the patient, practitioner or related person.</td></tr><tr><td>patient</td><td>reference</td><td>no</td><td>This is a <a href="https://github.com/GIDSOpenStandaarden/GIDS-HTI-Protocol/diffs/1?base_sha=0899d43a8ed3a53ccaf1ca3f1638753a28bdb7fb&#x26;branch=fhir-2-fields&#x26;commentable=true&#x26;name=fhir-2-fields&#x26;pull_number=23&#x26;qualified_name=refs%2Fheads%2Ffhir-2-fields&#x26;sha1=0899d43a8ed3a53ccaf1ca3f1638753a28bdb7fb&#x26;sha2=6f3ee98c1338f689c62e45a222d1e9e1d64142b8&#x26;short_path=baf3810&#x26;unchanged=expanded&#x26;w=false#person-reference">person reference</a> to the patient, only used when the 'sub' is not a patient</td></tr><tr><td>intent</td><td>string</td><td>no</td><td>The intention of the launch, this field should be used to provide the intention of the launch such as the preparation, performance or review of the resource, is used, a value from the <a href="https://www.hl7.org/fhir/R4/valueset-request-intent.html">FHIR value set RequestIntent</a></td></tr><tr><td>idp_hint</td><td>string</td><td>no</td><td>Informs the auth server to use a specific IdP for the user authentication. Should be filled with the logical identifier of the IdP. See <a href="https://vzvznl.github.io/Koppeltaal-2.0-FHIR/multiple-idp-support.html">the IG</a> for more information.</td></tr></tbody></table>

An example of the resulting HTI claims:

```javascript
{
    "resource": "Task/5f684c5f-2837-4505-a534-365431912f37",
    "definition": "ActivityDefinition/d76ba97b-bfce-4a75-8e7a-2133778d1089",
    "sub": "Practitioner/225d67a7-69b9-4343-b488-064945fe3fd3",
    "patient" : "Patient/b592f103-f75b-4a63-a5dd-b75799775258",
    "intent": "plan",
    "idp_hint": "primary-practitioner-idp"
}
```

### 2. Create the JWT

The `HTI:core` v2.0 profile also contains claims that are always set on a JWT:

| Description       | Field | Value                                                                                                                                                                                                                                                                                             |
| ----------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Issuer            | iss   | The `client_id` van het portaal                                                                                                                                                                                                                                                                   |
| Audience          | aud   | The device id of the module provider. This can be found via the `ActivityDefinition.resource-origin` extension.                                                                                                                                                                                   |
| Unique message id | jti   | A unique identifier for this message. This value **MUST** be treated as a NONCE, a subsequent message with an identical jti **MUST** be rejected. The jti value must be a random or pseudo number, the jti **MUST** contain enough entropy to block brute-force attacks.                          |
| Issue time        | iat   | The timestamp of generating the JWT token, the value of this field **MUST** be validated by the module provider to not be in the future.                                                                                                                                                          |
| Expiration time   | exp   | The "exp" (expiration time) claim identifies the expiration time on or after which the JWT **MUST NOT** be accepted for processing. The value **MUST** be limited to 5 minutes. This value **MUST** be validated by the module provider, any value that exceeds the timeout **MUST** be rejected. |

These two sets of claims should be combined to form a valid HTI v2.0 JWT. For example:

```json
{
  "iat": 1585564845,
  "aud": "Device/123",
  "iss": "portal-client-id",
  "exp": 1585565745,
  "jti": "679e1e4c-bcb9-4fcc-80c4-f36e7063545c"
  "sub" : "Practitioner/225d67a7-69b9-4343-b488-064945fe3fd3",
  "resource" : "Task/5f684c5f-2837-4505-a534-365431912f37",
  "definition" : "ActivityDefinition/d76ba97b-bfce-4a75-8e7a-2133778d1089",
  "patient" : "Patient/b592f103-f75b-4a63-a5dd-b75799775258",
  "intent": "plan"
}
```

The timestamps follows the ["UNIX time"](https://en.wikipedia.org/wiki/Unix_time) convention, being the number of seconds since the epoch.

### 3. Sign the JWT

After the JWT is completely filled, it must be signed. For this, [Signing the JWT](/technische-howto/connectie-maken-met-koppeltaal/requirements/jwt-ondertekenen) can be followed.

### 4. Launch

The signed token can now be launched to the client. To find the endpoint to be launched to, the `ActivityDefinition.endpoint` extension can be used. The correct ActivityDefinition can be found using `Task.instantiates` extension (see [Retrieve specific Resource](/technische-howto/resources-managen/crud-operaties/resource-ophalen)).

There are minimal differences between sending via [HTI](/technische-howto/launchen/hti-launch-versturen) and [SHOF](https://github.com/Koppeltaal/Koppeltaal-2.0-Hackathon-Dev-Guide/blob/master/technische-howto/launchen/launch-samenstellen/broken-reference/README.md).

## Topics

[TOP-KT-007 - Koppeltaal Launch](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123510/TOP-KT-007+-+Koppeltaal+Launch)


# Initiating a launch

The launch steps on this page are the same for HTI as SHOF

The launch can be initiated via a `<form>` and the `form-post-redirect` flow. Both HTI and SHOF are similar while initiating a launch.

```html
<html>
<head>
</head>
<body onload="document.forms[0].submit();">
<form action="https://module.provider.eu/modules/x" method="post">
<input type="hidden" name="launch" value="eyJhbGciO..."/>
<input type="hidden" name="iss" value="https://fhir-server.koppeltaal.headease.nl/fhir/DEFAULT"/>
</form>
</body>
</html>
```

## Launch

<mark style="color:green;">`POST`</mark> `{{ActivityDefinition.endpoint}}/`

This request initializes the launch.

#### Headers

| Name                                           | Type   | Description                         |
| ---------------------------------------------- | ------ | ----------------------------------- |
| Content-Type<mark style="color:red;">\*</mark> | String | `application/x-www-form-urlencoded` |

#### Request Body

| Name                                     | Type   | Description                                                  |
| ---------------------------------------- | ------ | ------------------------------------------------------------ |
| launch<mark style="color:red;">\*</mark> | String | [Signed JWT](/technische-howto/launchen/launch-samenstellen) |
| iss<mark style="color:red;">\*</mark>    | String | The URL of the Koppeltaal server                             |

## Topics

[TOP-KT-007 - Koppeltaal Launch](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123510/TOP-KT-007+-+Koppeltaal+Launch)


# Receiving a HTI launch

### Requirements

* The application [created](/technische-howto/resources-managen/crud-operaties/resource-aanmaken) an [`ActivityDefinition`](https://simplifier.net/koppeltaalv2.0/kt2activitydefinition).

#### When the application does not use [Token Introspection](/technische-howto/launchen/launch-ontvangen/token-introspection):

* The application must be able to map the `issuer` to its corresponding JWKS endpoint.

### Verify the JWT

Incoming HTI launches have a `launch` parameter. This value represents the signed JWT (see [Compose a launch](/technische-howto/launchen/launch-samenstellen))

#### Token Introspection

The easiest and safest way to verify the JWT is to use [Token Introspection](/technische-howto/launchen/launch-ontvangen/token-introspection). This way, the application itself does not have to verify all the security checks on the incoming JWT. The token can simply be forwarded to the authentication server and it will perform all the required checks.

#### Verify the JWT yourself

Using the issuer and the JWKS endpoint, the application can validate whether the JWT is actually signed by the private key of the asymmetric key pair. The JWK can be found using the kid (key id) field from the JWT Header section. For example:

![jwt.io debugger](https://1577345028-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiVMn-5GzUw-bGYHPT8%2Fuploads%2Fgit-blob-ccc9d7c7160a1957785817b2d2182dfc5a0da502%2FScreenshot%202021-09-22%20at%2020.22.09.png?alt=media)

This can be mapped to JWK objects from the JWKS endpoint:

```javascript
{
  "keys": [
    {
      "kty": "RSA",
      "kid": "oHV39B4Ow8hcw3SbkF4k0w",
      "use": "sig",
      "n": "ngtOwJ9jxRyRL1HSlVVF-TI6iv2Pf3kWm2fereynTNz06tZaOo8hm6FA0fucLHH1OxsFFa6rDNyVZcivbR3uEO4CKXrzDw5HUDxLh9qaR-PMolsz4s2mrz6xP9kGkVvQvuzJPQTQ4fat6aI7p0cyA5xA8vqUBqeYU323zcf8uUXb-qSJ3FpidDnTKLksD7B-yjU1HjDdDysRp8pNL6lVs5KW2L8XMCpbrvhyIQ_c5pwOrF_QzfsK9mW78wCKLJZ_D7eVw2yututBzm9z0pq5PColQP2nB7lq98DNJvDbmvMIfDNglRKTS-Qqky_S8a6H5gfgFTv77iaaFFjjld4cJw",
      "e": "AQAB"
    }
  ]
}
```

The JWK represents the public key that can be used to validate the signature.

### Other important checks

In addition to verifying the signature, the JWT payload contains fields that are important to validate.

| JWT claim (attribute)   | Details                                                                                                                                      | Implementation                                    |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| `exp` (expiration time) | After this time, the JWT is no longer valid                                                                                                  | Is often done automatically by JWT libraries      |
| `iat` (issued at)       | Issue date, it must not be in the future                                                                                                     | Is often done automatically by JWT libraries      |
| `jti` (JWT ID)          | Unique identifier for this JWT. The `jti` values used must be tracked. If a `jti` value has already been consumed, the JWT must be rejected. | Should most likely be implemented in custom logic |


# Token introspection

When an application receives an HTI launch, it will [contain a JWT token](/technische-howto/launchen/launch-samenstellen). To ensure that not every application has to build in all the security logic to verify this token, Koppeltaal offers [Token Introspection](https://datatracker.ietf.org/doc/html/rfc7662) on the authentication server. This eliminates the need for the application to [verify the JWT itself](/technische-howto/launchen/launch-ontvangen#verify-the-jwt-yourself).

When Token Introspection approves a token, the extracted body of the JWT token will be returned. If a `200` response code is returned, the application must ALWAYS verify that the `active` attribute in the response is `true`.

<mark style="color:green;">`POST`</mark> `{AUTH_SERVER_URL}/oauth2/introspect`

#### Headers

| Name                                           | Type   | Description                         |
| ---------------------------------------------- | ------ | ----------------------------------- |
| Content-Type<mark style="color:red;">\*</mark> | String | `application/x-www-form-urlencoded` |
| Accept<mark style="color:red;">\*</mark>       | String | `application/json`                  |

#### Request Body

| Name                                                      | Type   | Description                                                                                                              |
| --------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------ |
| client\_assertion<mark style="color:red;">\*</mark>       | String | <p>JWT as composed for the</p><p><a href="/pages/-Mj9lTQPchZnprqoGx2k#1.-jwt-samenstellen">SMART Backend Service</a></p> |
| client\_assertion\_type<mark style="color:red;">\*</mark> | String | <p>Always:</p><p><code>urn:ietf:params:oauth:client-assertion-type:jwt-bearer</code></p>                                 |
| token<mark style="color:red;">\*</mark>                   | String | The JWT to be validated                                                                                                  |

{% tabs %}
{% tab title="200" %}
{% tabs %}
{% tab title="Valid Token" %}

```json
{
  "active": true,
  "client_id": "l238j323ds-23ij4",
  "username": "jdoe",
  "scope": "read write dolphin",
  "sub": "Z5O3upPC88QrAjx00dis",
  "aud": "https://protected.example.net/resource",
  "iss": "https://server.example.com/",
  "exp": 1419356238,
  "iat": 1419350238,
  "extension_field": "twenty-seven"
}
```

{% endtab %}

{% tab title="Invalid Token" %}

```json
{
  "active": false
}
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="401" %}
Not authorised to execute introspection.
{% endtab %}
{% endtabs %}

## Topics

[TOP-KT-007 - Koppeltaal Launch](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123510/TOP-KT-007+-+Koppeltaal+Launch)

[TOP-KT-021 - Token Introspection](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27131284/TOP-KT-021+-+Token+Introspection)


# Receiving a SHOF launch

## Requirements

1. The application [created](/technische-howto/resources-managen/crud-operaties/resource-aanmaken) an [`ActivityDefinition`](https://simplifier.net/koppeltaalv2.0/kt2activitydefinition).
2. The user performing the launch must have an account on the shared IdP

## Flow

<figure><img src="https://1577345028-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiVMn-5GzUw-bGYHPT8%2Fuploads%2Fgit-blob-00cbadc8ba749a6b30f2b8e3c3a3b8a5165b424c%2FSMART%20on%20FHIR%20app%20launch%20and%20HTI.drawio%20(1).png?alt=media" alt="SMART HTI Flow"><figcaption><p>SMART HTI Flow</p></figcaption></figure>

1. When the launch arrives, the [conformance is retrieved from the Koppeltaal Server](/technische-howto/koppeltaal-server-metadata-opvragen). Here the authorize & token URL can be requested.
2. A redirect is sent to the authorize URL. The auth server will redirect the browser to a shared IdP using an OIDC code flow. If the launching platform does not use this shared IdP as a login mechanism, the user will have to login here as well. At the POC it is possible to create an account directly from this login screen. New users are given the role patient by default. The authorize call will check if the logged in user matches the user from the launch token.
3. A successful authorize call returns the `code` & `state` parameters to the `redirect_uri`. Note that the `state` (provided at the start of the `/authorize` call) is returned to the `redirect_uri`, this way you can find out which launch request is involved and, for example, relate to a specific user session.
4. From the back-end, execute the [Get Token request](#get-token). Here, the `code` is exchanged for:
   1. an `id_token` (contains information of the logged in user as `JWT`).
   2. A no-op `access_token` (not to be used on the Koppeltaal Server because it is user-specific).
   3. Additional context fields such as `task`, which the auth server fills based on the JWT provided as launch param.

By means of the context object it can be determined who, with which role, is logged on to the system and which task should be opened. When there is a valid response to this request, the user can be authenticated and e.g. a session can be created for the user.

## Authorize Request

<mark style="color:blue;">`GET`</mark> `https://auth-service.koppeltaal.headease.nl/oauth2/authorize`

The URL should be determined from the Koppeltaal metadata

#### Query Parameters

<table><thead><tr><th width="160">Name</th><th width="82">Type</th><th>Description</th></tr></thead><tbody><tr><td>aud<mark style="color:red;">*</mark></td><td>string</td><td>URL of the Koppeltaal server (the same as the <code>iss</code> value)</td></tr><tr><td>scope<mark style="color:red;">*</mark></td><td>string</td><td><p>Always:</p><p><code>launch openid fhirUser</code></p></td></tr><tr><td>state<mark style="color:red;">*</mark></td><td>string</td><td>An opaque value used by the client to maintain the state between the request and the callback. The authorization server takes this value when redirecting the user agent back to the client. The parameter MUST be used to prevent cross-site request forgery (CSRF) attacks or session fixation</td></tr><tr><td>launch<mark style="color:red;">*</mark></td><td>string</td><td>The HTI token (from the <code>launch</code>param)</td></tr><tr><td>redirect_uri<mark style="color:red;">*</mark></td><td>string</td><td><p>The URL to which the</p><p><code>code</code></p><p>should be returned</p></td></tr><tr><td>client_id<mark style="color:red;">*</mark></td><td>string</td><td>The <code>client_id</code> (from Domain Admin) of the application receiving the launch</td></tr><tr><td>response_type<mark style="color:red;">*</mark></td><td>string</td><td><p>Always:</p><p><code>code</code></p></td></tr><tr><td>code_challenge<mark style="color:red;">*</mark></td><td>String</td><td>A generated code challenge as per <a href="https://www.rfc-editor.org/rfc/rfc7636#appendix-B">rfc7636</a></td></tr><tr><td>code_challenge_method<mark style="color:red;">*</mark></td><td>String</td><td><p>Always:</p><p><code>S256</code></p></td></tr></tbody></table>

{% tabs %}
{% tab title="302" %}
The Location header will redirect with a code and the state

```
Location: https://launch-testsuite.koppeltaal.headease.nl/module_authentication_shof?code=05b542e2-6206-449b-924b-99d39168029b&state=99a8cf9a-28c2-4867-8123-486c04003482
```

{% endtab %}
{% endtabs %}

## Get Token

<mark style="color:green;">`POST`</mark> `https://authentication-service.koppeltaal.headease.nl/oauth2/token`

The URL should be determined from the Koppeltaal metadata

#### Headers

<table><thead><tr><th width="171">Name</th><th width="102">Type</th><th>Description</th></tr></thead><tbody><tr><td>Content-Type<mark style="color:red;">*</mark></td><td>String</td><td><code>application/x-www-form-urlencoded</code></td></tr></tbody></table>

#### Request Body

<table><thead><tr><th width="217">Name</th><th width="102">Type</th><th>Description</th></tr></thead><tbody><tr><td>client_assertion<mark style="color:red;">*</mark></td><td>String</td><td><p>JWT as composed for the</p><p><a href="/pages/-Mj9lTQPchZnprqoGx2k#1.-jwt-samenstellen">SMART Backend Service</a> for the application receiving the launch</p></td></tr><tr><td>client_assertion_type<mark style="color:red;">*</mark></td><td>String</td><td><p>Always:</p><p><code>urn:ietf:params:oauth:client-assertion-type:jwt-bearer</code></p></td></tr><tr><td>redirect_uri<mark style="color:red;">*</mark></td><td>string</td><td>The same <code>redirect_uri</code> as used at the authorize request</td></tr><tr><td>code<mark style="color:red;">*</mark></td><td>string</td><td><code>code</code> provided by the auth server on the redirect from the authorize request</td></tr><tr><td>grant_type<mark style="color:red;">*</mark></td><td>string</td><td><p>Always:</p><p><code>authorization_code</code></p></td></tr><tr><td>code_verifier<mark style="color:red;">*</mark></td><td>String</td><td><p>Unhashed value used foe generating the <code>code_challenge</code> in the authorize step as per</p><p><a href="https://www.rfc-editor.org/rfc/rfc7636#appendix-B">rfc7636</a></p></td></tr></tbody></table>

{% tabs %}
{% tab title="200" %}
The OIDC response plus additional context fields used in the launch is returned

```json
{
  "access_token": "NOOP",
  "id_token": "eyJraWQiOiJvUDQ4NmxJcmwzRFFQdXF0dVVqUmxqc01oWFA0alJmdXoxS19uX0dpQmRrIiwiYWxnIjoiUlM1MTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLXNlcnZpY2Uua29wcGVsdGFhbC5oZWFkZWFzZS5ubC8iLCJhdWQiOiJiMDJkNmVhNi1iMWEyLTRjZDQtODJmNS1iNjQyM2Q2NmE5ODgiLCJuYmYiOjE2MzI4MTMzNTAsImV4cCI6MTYzMjgxNjk1MCwibm9uY2UiOiJmNGMxODZlNy1jMzI2LTQxODAtYjFmMi1jYTllMWI4YTgyYWQiLCJzdWIiOiJQYXRpZW50LzE5NjMiLCJhenAiOiJiMDJkNmVhNi1iMWEyLTRjZDQtODJmNS1iNjQyM2Q2NmE5ODgifQ.UfBtTACLOhsCMr4Tlen3RUFek06WgWc-aaTPQzJzmHVGYBLY3CnJXTLI1FfCzp1ChM3vx-e2jbFCDHak6ennsuitki-1HnrZitTKpG8qKZK_f24gwVFM5LmzdUXtuTszJSeulpRG8zmNI96pqaIW4ru995LwhKLd-XSOY02BbAMo4XZ46ZW8DBXnhr32CI9TUza8NEQoxlQAF8EboUhro5vauPrjdshP3jQFUNSs5NceB4er3RnF10Zd6SiLFP-_c2ynaj_v87fJEgVGw63byYcKm6O3bTW2KsSz_YNYDYv8DWjYAp25P79e-Hlc3ERcybhLnLy0_-Rkvjk5P_240g"
  "scope": "openid fhirUser launch",
  "token_type": "Bearer",
  "expires_in": "3600",
  "resource": "Task/37fa63e3-b118-4180-8470-74b1df508bf6",
  "definition": "ActivityDefinition/64b95e9a-e0fa-49ea-9cc5-00ff61300d3d",
  "sub": "Practitioner/52b6535b-4e69-455b-9d9f-952e708ad393",
  "patient": "Patient/70184602-4d15-4ca9-89a6-00e78123b22e",
  "intent": "plan"
}
```

{% endtab %}
{% endtabs %}

## Topics

[TOP-KT-007 - Koppeltaal Launch](https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27123510/TOP-KT-007+-+Koppeltaal+Launch)


# Detailed technical guidance

The developer guide helps out to get started. But of course, there is more to Koppeltaal. There are multiple resources that can be used when you need more advanced technical guidance

## Implementation Guide

When you implementation specific use-cases, and want to know if Koppeltaal has any specific implementation rules for that use-case, the Implementation Guide can be used.

{% embed url="<https://simplifier.net/guide/koppeltaal?version=current>" %}

## Simplifier profile

When you need to grasp the data structures used in Koppeltaal, it's best to look at the simplifier profile. This profile contains all the supported resources, its attributes and cardinalities. As well, it contains useful examples that can help you get started.&#x20;

#### Finding the current profile version

Profiles evolve, and have multiple versions. To look at the exact version used on the server, you can [request](/technische-howto/koppeltaal-server-metadata-opvragen) the server `/metadata`. The `/metadata` shows the server's `CapabilityStatement`. The `CapabilityStatement.implementationGuide` should point to a KT2 `ImplementationGuide` resource. This is a canonical reference, and thus points to an `ImplementationGuide.url` value. Currently, it points to `http://koppeltaal.nl/fhir/ImplementationGuide`.&#x20;

So, for the reference implementation, it can be requested as such:

{% embed url="<https://fhir-server.koppeltaal.headease.nl/fhir/DEFAULT/ImplementationGuide?url=http%3A%2F%2Fkoppeltaal.nl%2Ffhir%2FImplementationGuide>" %}

This resource contains a `version` field that corresponds to the released version of simplifier used on the server.

#### Looking at the specific Simplifier version

After [finding the current profile version](#finding-the-current-profile-version), navigate to the simplifier packages history page and match the version:

{% embed url="<https://simplifier.net/packages/Koppeltaalv2.00/0.14.0-beta.7/~history>" %}

Opening up a specific version shows all the details of the specific package. The `Files` tab shows all files that are packages in the released. In here you can also find the profile details of that specific version.

## Koppeltaal 2.0 Specification & Architecture

Most of the documentation is already linked to the specific topics of the Koppeltaal 2.0 Specification & Architecture. These specifications contain a very detailed description of the functionality in Koppeltaal, but also all technical requirements. The requirements can be found in the topics

{% embed url="<https://vzvz.atlassian.net/wiki/spaces/KTSA/pages/27115333/Standaard+topics>" %}
KT2.0 topics
{% endembed %}

{% embed url="<https://vzvz.atlassian.net/wiki/spaces/KTSA/overview>" %}
KT 2.0 Specification & Architecture
{% endembed %}


# Requirements

To implement the use cases, several tasks must be completed:

1. The IRMA app must be installed
2. An email address attribute must have been added to IRMA
3. The application must be able to [connect to Koppeltaal](/technische-howto/connectie-maken-met-koppeltaal)


# Install and configure Yivi

See the [Joining a domain](/domain-access/domein-toetreden) page


# Use-Cases

The hackathon consists of four use-cases. These use-cases focus on the FHIR `Task` resource. This Resource is the core of Koppeltaal and references other important Resources. At the end of the hackathon, we would like to see the following use-cases working:

1. Assign a `Task` to a `Patient` as a `Practitioner`.
2. Launch a `Task` from a patient portal using [HTI](/technische-howto/launchen).
3. Launch a `Task` from a patient portal using [SMART HTI On FHIR](https://github.com/Koppeltaal/Koppeltaal-2.0-Hackathon-Dev-Guide/blob/master/hackathon-use-cases/crud-task/broken-reference/README.md).
4. Subscribe to changes


# Use-Case 1: Create a Task

{% hint style="info" %}
When referenced Resources need to be created that are required for Task creation (e.g. `ActivityDefinition` or `Endpoint`), the [EHR](https://poc-epd.koppeltaal.headease.nl/) can be used. As the Resources are created by a different application, make sure that your application has the [rights](/domain-access/rollen-beheren/autorisatiemodel) to see/use these Resources.
{% endhint %}

{% hint style="warning" %}
When using the EHR to create Resources, it is important to look in simplifier for the mandatory fields of the Resources. The EHR itself does not indicate which fields are mandatory, and does not return information about why a Resource could not be created.
{% endhint %}

### Task creation

Creating a `Task` in the Koppeltaal server works just like any other Resource: using the RESTful API.

The `Task` resource can most easily be created using an official FHIR library. First consult the [FHIR Downloads page](https://hl7.org/fhir/r4/downloads.html) to see if you can find a useful library. The final output of the code should be a `POST` request to the Koppeltaal server. More information on creating resources is described [here](/technische-howto/resources-managen/crud-operaties/resource-aanmaken).

#### Profile

The Koppeltaal server enforces compliance with the [Koppeltaal KT2Task profile](https://simplifier.net/koppeltaalv2.0/kt2task). The `Task` Resource must indicate that it's using the KT2Task profile. This is done in the `Resource.meta.profile` field.

#### Example Task

```json
{
  "resourceType": "Task",
  "meta": {
    "profile": [
      "http://koppeltaal.nl/fhir/StructureDefinition/KT2Task"
    ]
  },
  "identifier": [
    {
      "system": "https://poc-portal.koppeltaal.headease.nl",
      "value": "a4fb3572-e82c-421d-aca3-42c26face61a"
    }
  ],
  "instantiatesCanonical": "https://hapi-fhir-server.koppeltaal.headease.nl/fhir/ActivityDefinition/762/_history/1",
  "status": "ready",
  "intent": "order",
  "executionPeriod": {
    "start": "2021-09-21T10:50:20+02:00"
  },
  "owner": {
    "reference": "Patient/00216d69-9c36-4c42-8837-8ee1bbc9c926"
  }
}
```


# Create an ActivityDefinition

{% hint style="warning" %}
Applications that can be launched MUST be the publisher of the `ActivityDefinition`.&#x20;
{% endhint %}

Koppeltaal adds three [extensions](https://simplifier.net/koppeltaalv2.0/kt2activitydefinition) to the `ActivityDefinition` resource:

<figure><img src="https://1577345028-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MiVMn-5GzUw-bGYHPT8%2Fuploads%2Fgit-blob-3c89fe2f9f2050ab8a97e161f2b4a8dbc4121554%2FScreenshot%202023-02-09%20at%2009.25.51.png?alt=media" alt=""><figcaption></figcaption></figure>

| Extension       | Description                                                                                                                                                                                                                                                                                                                                                                                                  |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| endpoint        | Every `ActivityDefinition` must refer to an `Endpoint` Resource. The value of this `Endpoint` must be filled with the URL that the user is sent to while launching a `Task` that uses this `ActivityDefinition`                                                                                                                                                                                              |
| publisherId     | A unique identifier for the client publishing the `ActivityDefinition`. This can be used to, for example, retrieve all Tasks that refer to any `ActivityDefinition` from publisher ***X***. This can be very useful for subscribing to changes in `Tasks` that are relevant to your application. This value requires an `id` type value, allowing more freedom of "groups" than the `resource-origin` field. |
| resource-origin | A reference to the `Device` that created the Resource. This is set by the Koppeltaal server as it's used by the [authorisation mechanism](/domain-access/rollen-beheren/autorisatiemodel). This value cannot be set by the client while creating new Resources.                                                                                                                                              |

### Example ActivityDefinition

```javascript
{
    "resourceType": "ActivityDefinition",
    "meta": {
        "profile": [
            "http://koppeltaal.nl/fhir/StructureDefinition/KT2ActivityDefinition"
        ]
    },
    "extension": [
        {
            "url": "http://koppeltaal.nl/fhir/StructureDefinition/KT2PublisherIdentifier",
            "valueId": "ID345900-002"
        },
        {
            "url": "http://koppeltaal.nl/fhir/StructureDefinition/KT2EndpointExtension",
            "valueReference": {
                "reference": "Endpoint/04230feb-8cf6-458b-bb46-409430f64701",
                "type": "Endpoint"
            }
        }
    ],
    "url": "http://Testtooling.com/ActivityDefinition/",
    "identifier": [
        {
            "use": "official",
            "system": "http:/vzvz.nl/Testtooling",
            "value": "Controlelijst voortgang"
        }
    ],
    "version": "1.1.0",
    "name": "Controlelijst",
    "title": "Controlelijst voortgang",
    "status": "active",
    "description": "Vul de controlelijst zo goed mogelijk in. Dit kost ongeveer 10 minuten."
}
```


# Use-Case 2: HTI Launch

Launching a Task via HTI

This use case showcases the lightweight launch from one client to another by using HTI. The [launch section](/technische-howto/launchen) describes how to implement the HTI launch.

### Composing a launch

{% hint style="info" %}
This step is identical between HTI and SHOF
{% endhint %}

The documentation [Compose a launch](/technische-howto/launchen/launch-samenstellen) explains in detail how to this should be done.

### Receiving a HTI launch

The documentation [Receiving a HTI launch](/technische-howto/launchen/launch-ontvangen) explains in detail how to handle being launched to via HTI.


# Use-case 3: SHOF Launch

Launching a Task via SMART HTI On FHIR (SHOF).

This use-case ensures that clients can launch in a similar way to Koppeltaal 1.x. In addition, the SHOF launch performs an additional security check that ensures the launch token is not intercepted and executed by someone else.

### Composing a launch

{% hint style="info" %}
This step is identical between HTI and SHOF
{% endhint %}

The documentation [Compose a launch](/technische-howto/launchen/launch-samenstellen) explains in detail how to this should be done.

### Receiving a SHOF launch

The documentation [Receiving a SHOF launch](/technische-howto/launchen/smart-hti-on-fhir-launch-ontvangen) explains in detail how to handle being launched to via SHOF.

### Testing

The SHOF Launch can be tested using the [Launch Test Suite](https://launch-testsuite.koppeltaal.headease.nl/portal.html) to launch to the POC module. You can launch to the POC module using the following parameters in the Test Suite:

| Attribute      | Value                                                     |
| -------------- | --------------------------------------------------------- |
| Audience (aud) | <https://poc-module.koppeltaal.headease.nl/module_launch> |
| Launch url     | <https://poc-module.koppeltaal.headease.nl/module_launch> |


# Use-case 4: Subscribing to changes

To receive notifications on important resources, applications can create their own `Subscription` resources. Follow [this](/technische-howto/resources-managen/abonneren-op-changes) page and try subscribing to `Task` changes.


