SSO from ZorgDomein
Introduction
ZorgDomein supports single sign on (SSO) to external applications (“apps”) for both practitioners and patients that use ZorgDomein. After SSO to an app, this app can exchange data with ZorgDomein through a FHIR API. This SSO-mechanism is based on SMART on FHIR, see SMART Application Launch Framework Implementation Guide 1.0.0 for detailed documentation. This framework uses the OpenID Connect specification for authentication of a platform user to a third party app. Authorization to the FHIR API of the platform application is established through OAuth 2.0. The SMART on FHIR specification defines two different ways for launching an external application:
- EHR launch: the application launches from an existing EHR or Patient Portal session.
- Standalone launch: the application launches as a standalone application and actively requests user authentication at the EHR.
ZorgDomein only supports the EHR launch (where ZorgDomein takes the role of an EHR).
Public vs confidential apps
The OAuth2 specification defines two types of apps: confidential and public apps. The differentiation is based upon whether the execution environment within which the app runs enables the app to protect secrets. Confidential apps are able to protect secrets, public apps aren’t. A client secret may be used to authenticate the app when requesting access tokens. Pure client-side apps (for example, HTML5/JS browser-based apps, iOS mobile apps, or Windows desktop apps) apps can provide adequate security, but they may be unable to “keep a secret” in the OAuth2 sense. In other words, any “secret” key, code, or string that is statically embedded in the app can potentially be extracted by an end-user or attacker. Hence security for these apps cannot depend on secrets embedded at install-time. ZorgDomein considers all apps as public apps. This means that we don’t issue client secrets, and that we do not require HTTP authentication when requesting access tokens.
The SSO mechanism involves four different system roles:
- Browser: the internet browser that presents the user interface to the end user
- App server: the web server of the third party application
- FHIR server: the server that exposes an API to the ZorgDomein application
- Auth server: the server that manages authorization of users. This server is maintained by ZorgDomein.
Interaction sequence
During the process of SSO these systems exchange data according to the flow displayed in the diagram below.
The flow starts with an authenticated user in ZorgDomein. As displayed in the diagram the flow consists of the following steps:
1. Launch app
The user wants to navigate to an external application. To facilitate this the ZorgDomein frontend exposes a launch URL that points to the external application. The user navigates to this URL in the browser, so the browser issues a HTTP GET request to the launch URL of the application server. The launch URL will contain the following query parameters:
launch
– opaque identifier for this specific launch. This parameter must be communicated back to ZorgDomein at authorization time by passing along a launch parameter (see step 4/5).iss
– fixed value:https://www.zorgdomein.nl/api/fhir/stu3
(base FHIR endpoint of ZorgDomein).
Example launch URL:
https://my.smart-app.com/oauth/login?
launch=twjAavxomS4ZpGcu
&iss=https%3A%2F%2Fwww.zorgdomein.nl%2Fapi%2Ffhir%2Fstu3
2. Requests authorization URLs
On receiving the launch notification, the app sends an HTTP GET request to the ZorgDomein FHIR server to query ZorgDomein’s Well-Known Uniform Resource Identifiers JSON document (www.zorgdomein.nl/api/fhir/stu3/.well-known/smart-configuration). This resource contains (among other details) the OAuth authorization and token endpoints of ZorgDomein. The app needs these endpoints to request authorization at ZorgDomein in step 4.
3. Provide authorization URLs
The ZorgDomein FHIR server will respond with a Well-Known URI’s JSON document. The endpoint values can be extracted from the response (see example below).
{
"authorization_endpoint": "https://www.zorgdomein.nl/api/oauth/authorize",
"token_endpoint": "https://www.zorgdomein.nl/api/oauth/token",
"token_endpoint_auth_methods_supported": [
"none"
],
"scopes_supported": [
"openid",
"profile",
"email",
"address",
"phone",
"online_access",
"http://zorgdomein.nl/terminology/naming-system/zd-number"
],
"capabilities": [
"launch-ehr",
"client-public",
"context-ehr-patient",
"sso-openid-connect"
]
}
4. Redirect to ZorgDomein authorization URL
To send a request for an authorization code to the ZorgDomein authorization server, the app sends a HTTP redirect response to the browser, redirecting to the authorization URL with the following query parameters:
response_type
– Fixed value:code
(the OAuth authorization code flow is used, see Open ID specifications for details)client_id
– The client’s identifier. This identifier will be exchanged between ZorgDomein and app supplier during the registration process (see Registration of SMART apps).redirect_uri
– Must match one of the redirect URLs that have been registered at ZorgDomein during the registration process.launch
– Must contain the value of the launch id issued by ZorgDomein in step 1.scope
– Describes the access that the app needs. Multiple scopes can be defined separated by a space. Supported values:openid
– request an OpenID token .profile
– request access to the user’s default profile claims in the OpenID token. The following claims are supported and may be included in the ID token:name
,family_name
,given_name_initials
,gender
andbirthdate
.email
– request access to theemail
andemail_verified
claims.address
– requests access to theaddress
claim in the OpenID token (see Open ID specifications for details).phone
– request access to thephone_number
andphone_number_verified
claims in the OpenID token.http://zorgdomein.nl/terminology/naming-system/zd-number
– request the ZD number of the current transaction in ZorgDomein at launch time.http://zorgdomein.nl/terminology/scopes/transaction-actors-agb
– request the AGB codes of the actors (sending and receiving organization) of the current transaction in ZorgDomein at launch time.
state
– An opaque value used by the app to maintain state between the request and callback. The ZorgDomein authorization server includes this value when redirecting the browser back to the app (see step 8). The parameter SHALL be used for preventing cross-site request forgery or session fixation attacks.nonce
(optional) – String value used to associate a client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the authentication request to the ID Token. For implementation notes, see section 15.5.2 of the OpenID specifications.aud
– Base URL of the ZorgDomein FHIR server:https://www.zorgdomein.nl/api/fhir/stu3
. This parameter prevents leaking a genuine bearer token to a counterfeit resource server. Note: thisaud
value is the same as the launch’siss
value.
Example redirect URL:
https://www.zorgdomein.nl/api/oauth/authorize?
response_type=code
&client_id=mysmartappid
&redirect_uri=https%3A%2F%2Fmy.smart-app.com%2Foauth%2Fgetaccesstokenforcode
&launch=twjAavxomS4ZpGcu
&scope=openid%20profile%20email%20phone%20launch%2Fpatient%20patient%2FAppointment.write%20online_access
&state=X2HO7ZxXTd7NNwe3
&aud=https%3A%2F%2Fwww.zorgdomein.nl%2Fapi%2Ffhir%2Fstu3
5. Request authorization page
Following the HTTP redirect that the browser receives from the app, the browser sends a HTTP GET request to the ZorgDomein authorization page. Through this page the app can request an authorization code.
6. Serve authorization page
ZorgDomein responds with the authorization page which presents the authorization request to the user.
7. Send user approval
The user reviews and approves the authorization request. The browser sends the authorization approval to the ZorgDomein authorization server.
8. Provide authorization code to browser
When approval has been received, the ZorgDomein authorization server generates an authorization code and communicates this code to the app server through an HTTP redirect to the app server. This causes the browser to redirect to the redirect_uri
(as provided in step 4) with the following query parameters:
code
– The authorization code generated by the authorization server.state
– The exact value received from the app server in step 4.
Example redirect URL:
https://my.smart-app.com/oauth/getaccesstokenforcode?
code=q9kNvFCZSUNdOoAat2CaD229bl6744dD&
&state=X2HO7ZxXTd7NNwe3
9. Provide authorization code to app
Following the redirect command received from the ZorgDomein authorization server, the browser sends a HTTP GET request to the redirect_uri
(i.e. the app) containing the authorization code
and state
parameters.
10. Request access token
After obtaining the authorization code, the app trades the code for an access token via HTTP POST to the ZorgDomein authorization server’s token endpoint URL, using content-type application/x-www-form-urlencoded
. The following form parameters must be included in the POST:
grant_type
– Fixed value:authorization_code
.code
– Code that the app received from the ZorgDomein authorization server.redirect_uri
– The sameredirect_uri
used in the initial authorization request (step 4).
Example POST request:
POST /api/oauth/token HTTP/1.1
Host: www.zorgdomein.nl
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=q9kNvFCZSUNdOoAat2CaD229bl6744dD
&redirect_uri=https%3A%2F%2Fmy.smart-app.com%2Foauth%2Fgetaccesstokenforcode
11. Provide access token and ID token
ZorgDomein authorization server responds with a JSON object that contains the following parameters:
access_token
– The access token issued by the ZorgDomein authorization server.token_type
– Fixed value:Bearer
.expires_in
– Lifetime in seconds of the access token, after which the token will not be accepted by the ZorgDomein FHIR server.scope
– Scope of access authorized. Note that this can be different from the scopes requested by the app.id_token
– Authenticated user identity and details. See ID token documentation for details.refresh_token
– Token that can be used to obtain a new access token, using the same or a subset of the original authorization grants.patient
- ID of the FHIR Patient resource representing the active patient content in ZorgDomein.http://zorgdomein.nl/terminology/naming-system/zd-number
– ZD number of the active transaction in ZorgDomein at launch time.http://zorgdomein.nl/terminology/sso-parameters/callback-uri
– URL the app should use when sending the user back to ZorgDomein when closing the app.http://zorgdomein.nl/terminology/sso-parameters/sending-organization-agb
- AGB code of the sending organization for the active transaction in ZorgDomein at launch time.http://zorgdomein.nl/terminology/sso-parameters/receiving-organization-agb
- AGB code of the receiving organization for the active transaction in ZorgDomein at launch time.
Example access token response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJjbGllbnRfaWQiOiJteXNtYXJ0YXBwaWQiLCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIHBob25lIGxhdW5jaC9wYXRpZW50IGxhdW5jaC96ZG51bWJlciBwYXRpZW50L0FwcG9pbnRtZW50LndyaXRlIG9ubGluZV9hY2Nlc3MiLCJ1c2VyIjoiMWFmMjE2ZTQtNjFjYy00ZmE0LWJhOTMtYzE3MDhhZTVmNmUwIiwicGF0aWVudCI6IjliZTA3NDA4LWUyMDYtNGQ1Zi05YmRjLTcwMjRjMTg3NzY5YiIsInpkbnVtYmVyIjoiWkQxMjM0NTY3OCIsImlhdCI6MTU3MTMyNTg2MywiZXhwIjoxNTcxMzI3NjYzfQ.mdESytoX3Bl-3F1ag86_xe0YVigyaEV7BsvzVhYo9y4",
"token_type": "Bearer",
"expires_in": 1800,
"scope": "openid profile email phone launch/patient patient/Appointment.write online_access",
"id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Inpvcmdkb21laW4tMjAxOTEwMTcxMTMwMDUzMCJ9.eyJpc3MiOiJodHRwczovL3pvcmdkb21laW4ubmwiLCJzdWIiOiIxYWYyMTZlNC02MWNjLTRmYTQtYmE5My1jMTcwOGFlNWY2ZTAiLCJhdWQiOiJteXNtYXJ0YXBwaWQiLCJleHAiOjE1NzEzMjc2NjMsImlhdCI6MTU3MTMyNTg2MywibmFtZSI6IkluZ3JpZCBUZXN0Z2VicnVpa2VyIC0gdmFuIFpvcmdEb21laW4iLCJmYW1pbHlfbmFtZSI6IlRlc3RnZWJydWlrZXIgLSB2YW4gWm9yZ0RvbWVpbiIsImdpdmVuX25hbWUiOiJJbmdyaWQiLCJnZW5kZXIiOiJmZW1hbGUiLCJiaXJ0aGRhdGUiOiIxOTc2LTEwLTE0IiwiZW1haWwiOiJpbmdyaWRAbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYWRkcmVzcyI6eyJmb3JtYXR0ZWQiOiJTdHJhYXR3ZWcgNjhcclxuMzYyMSBCUlxyXG5CcmV1a2VsZW4iLCJzdHJlZXRfYWRkcmVzcyI6IlN0cmFhdHdlZyA2OCIsImxvY2FsaXR5IjoiQnJldWtlbGVuIiwicG9zdGFsX2NvZGUiOiIzNjIxIEJSIn0sInBob25lX251bWJlciI6IjA2MTIzNDU2NzgiLCJwaG9uZV9udW1iZXJfdmVyaWZpZWQiOnRydWV9.KwfKMjvN3VXZr-Cs1gpgfZv6SrVGLp7F0uGdOIUm8Eg",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJjbGllbnRfaWQiOiJteXNtYXJ0YXBwaWQiLCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIHBob25lIGxhdW5jaC9wYXRpZW50IGxhdW5jaC96ZG51bWJlciBwYXRpZW50L0FwcG9pbnRtZW50LndyaXRlIG9ubGluZV9hY2Nlc3MiLCJ1c2VyIjoiMWFmMjE2ZTQtNjFjYy00ZmE0LWJhOTMtYzE3MDhhZTVmNmUwIiwicGF0aWVudCI6IjliZTA3NDA4LWUyMDYtNGQ1Zi05YmRjLTcwMjRjMTg3NzY5YiIsInpkbnVtYmVyIjoiWkQxMjM0NTY3OCIsImlhdCI6MTU3MTMyNTg2M30.vc5rOoaRWS3wqzTG_UcEG1LGl1MKVHCmpMtAmumnYbA",
"patient": "9be07408-e206-4d5f-9bdc-7024c187769b",
"http://zorgdomein.nl/terminology/naming-system/zd-number": "ZD12345678",
"http://zorgdomein.nl/terminology/sso-parameters/callback-uri": "https://www.zorgdomein.nl/patient/referral/e09abe15-1ef6-40c6-8d8c-bb6816e36fb5/detail"
}
The signature of the ID token must be validated using the public key that ZorgDomein provides. The payload of the ID token should be used to create a user session in the app. The access token may be used to authorize future requests to the ZorgDomein FHIR server. Currently ZorgDomein does not expose any FHIR endoints, but that may change in the future.
12. SSO complete, serve app start page
After all user details have been obtained, a user session can be initiated in the app which completes the app launch. The app start page is sent to the browser.
ID token specifications
The ID token that ZorgDomein provides in the access token response (step 11) is a JWT (JSON web token). This is a token that consists of a header, a payload and a signature. See the OpenID token specifications for detailed documentation.
ID token header
The ID token header contains the following elements:
alg
– fixed value:RS256
. Indicates that tokens are signed using the RSA SHA-256 algorithm.typ
– fixed value:JWT
. Indicates that this is a JSON web token.kid
– id of the key that was used to sign the token. This is issued by ZorgDomein upon registration of the app.
Header example:
{
"typ": "JWT",
"alg": "RS256",
"kid": "zorgdomein-2019101711300530"
}
ID token payload
The payload of the ID token contains the following claims:
iss
– Fixed value:https://zorgdomein.nl/
.sub
– Subject identifier. A locally unique and never reassigned identifier within ZorgDomein for the user. Thesub
value is a case sensitive string.aud
– Audience(s) that this ID Token is intended for. It will contain the OAuth 2.0client_id
of the app. This is a single case sensitive string.exp
– Expiration time on or after which the ID Token MUST NOT be accepted for processing.iat
– Time at which the JWT was issued. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time.nonce
(optional) – String value used to associate an app session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the authorization request (step 4/5) to the ID Token. If present in the ID Token, the app MUST verify that the nonce claim value is equal to the value of the nonce parameter sent in the authorization request. The nonce value is a case sensitive string.name
(optional) – Full name of the user in displayable form including all name parts, possibly including titles and suffixes.family_name
(optional) – Surname(s) or last name(s) of user.given_name_initials
(optional) - Initials of the user’s given name.gender
(optional) – Gender of the user (female or male).birthdate
(optional) – Birthday of the user, represented as an YYYY-MM-DD format.email
(optional) – Preferred e-mail address of the user.email_verified
(optional) –true
if the user’s e-mail address has been verified; otherwisefalse
.address
(optional) – Preferred postal address of the user. This value is a JSON object containing some or all of the members defined in section 5.1.1 of the OpenID specifications.phone_number
(optional) – Preferred telephone number of the user.phone_number_verified
(optional) –true
if the user’s phone number has been verified; otherwisefalse
.http://zorgdomein.nl/terminology/identity-claims/bsn
(optional) - BSN of the user.
Payload example:
{
"iss": "https://zorgdomein.nl",
"sub": "1af216e4-61cc-4fa4-ba93-c1708ae5f6e0",
"aud": "mysmartappid",
"exp": 1571327663,
"iat": 1571325863,
"name": "Ingrid Testgebruiker - van ZorgDomein",
"family_name": "Testgebruiker - van ZorgDomein",
"gender": "female",
"birthdate": "1976-10-14",
"email": "ingrid@mail.com",
"email_verified": true,
"address": {
"formatted": "Straatweg 68\r\n3621 BR\r\nBreukelen",
"street_address": "Straatweg 68",
"locality": "Breukelen",
"postal_code": "3621 BR"
},
"phone_number": "0612345678",
"phone_number_verified": true,
"http://zorgdomein.nl/terminology/identity-claims/bsn": "12344321"
}
ID token signature
Following the JWT specification, the signature is generated using the encoded header, the encoded payload, and both the key pair and algorithm specified in the header. This signate must be validated before processing the payload of the ID token and creating a new user session!
Returning to ZorgDomein
Once SSO has succeeded and the user has logged in to the app, the app must provide a button in its user interface that enables the user to navigate back to ZorgDomein. This button must direct the user to the url provided in the http://zorgdomein.nl/terminology/sso-parameters/callback-uri
attribute of the access token response.
If the SSO flow is used to enable the user to schedule an appointment in the app, a booked
query parameter must be appended to this callback uri, having one of the following values:
booked=1
if an appointment was scheduledbooked=0
if no appointment was scheduled
App registration
ZorgDomein does not support automated registration of apps. If you are the vendor of an app that you want to register at ZorgDomein, please contact us. When applying for registration of your app, please supply the following details:
- A fully specified launch URL
- A fully specified redirect URL
After successful registration we will provide the following details:
- The
client_id
parameter for your app - The public key or certificate you can use the validate our ID tokens
Validation criteria
Before a connector with ZorgDomein can be released, ZorgDomein will validate the connector against a set of validation criteria. The functional criteria for this component are listed below.
The app must:
- support creating a user session based on the details provided in the ID token
- provide a button to the user to return to ZorgDomein.
Questions or comments?
Leave your details below, we will contact you asap.