Skip to content

Report Providers API

Joël Spaltenstein edited this page Jan 29, 2020 · 77 revisions

Report Providers

A Report Provider can receive an Access Token via two different flows, the Implicit flow and the Authorization Code flow. With the Implicit flow, the Access Token will be provided as a fragment parameter directly to the redirect_uri. With the Authorization Code flow, an Authorization Code will be delivered to the redirect_uri via a query parameter. The Report Provider will then exchange the Authorization Code for an Access Token by calling and authenticating with the token_endpoint.

Configuration URL

The Configuration URL is an http or https endpoint on standard ports (80, 443) that returns a JSON object with the following parameters:

redirect_uri: REQUIRED Where the user will be redirected when the report provider is selected.
response_type: REQUIRED Can be set to 'token' or 'code' in order to determine which flow to use, Implicit or Authorization Code, respectively.

scope: OPTIONAL Can be used to request a limited scope. For example, 'read' to only receive readonly tokens. Default is 'read write'. not implemented yet
study_multiplicity: OPTIONAL Can be used to signal that the Report Provider can process multiple studies at once. Can be set to 'single', 'multiple', or 'all'. Default is 'single'. not implemented yet
modalities_supported: OPTIONAL Array of modality strings. The Report Provider will only be displayed for studies that contain at least one series with a supported modality. Defaults to all modalities. not yet implemented
client_name: OPTIONAL Human-readable string name of the Report Provider to be presented to the end-user.
client_uri: OPTIONAL URL string of a web page providing information about the Report Provider.
contacts: OPTIONAL Array of strings representing ways to contact people responsible for this Report Provider, typically email addresses.
tos_uri: OPTIONAL URL string that points to a human-readable terms of service document for the Report Provider that describes a contractual relationship between the end-user and the Report Provider that the end-user accepts when using the Report Provider.
policy_uri: OPTIONAL URL string that points to a human-readable privacy policy document that describes how the deployment organization collects, uses, retains, and discloses personal data.
software_version: OPTIONAL A version identifier string for the Report Provider software.

If the response_type is set to 'code' the following additional parameters are required.

token_endpoint_auth_method: REQUIRED Must be set to 'private_key_jwt' since this is the only auth method currently supported.
token_endpoint_auth_signing_alg: REQUIRED Must be set to 'RS256'.
jwks_uri: REQUIRED URL string the points to the JWKS formatted public key for this report provider. For the JWKS URI, the kty parameter must be 'RSA' and the alg parameter must be 'RS256' (the second key in the array at https://tools.ietf.org/html/rfc7517#appendix-A.1 is a good example)

The Configuration URL, the redirect_uri, and the jwks_uri must all share the same scheme and host.

Example

The configuration returned by https://reportprovider.kheops.online is:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "redirect_uri":"https://reportprovider.kheops.online/report.html",
    "response_type":"code",
    "jwks_uri":"https://reportprovider.kheops.online/certs",
    "token_endpoint_auth_method":"private_key_jwt",
    "token_endpoint_auth_signing_alg":"RS256",
    "supported_modalities":["CT", "MR", "PET"],
    "client_name":"Kheops Report Provider",
    "client_uri":"https://kheops.online",
    "contacts":["contact@kheops.online"]
}

Implicit (token) flow

When the user activates the Report Provider, the user will be redirected to the redirect_uri with the following additional query parameters.

access_token: The Access Token.
token_type: Will always be bearer.
expires_in: Time in seconds that the Access Token will be valid.
scope: Scope of the Access Token. For example 'read' or 'read write'. Note that if the user activating the Report Provider does not have write access, the scope will not include write.
conf_uri: URL string that points to the configuration of the Report Provider on the Kheops instance.
client_id: The client ID of the Report Provider on the Kheops instance.
return_uri: URL to which to send the user when returning the user's user agent to Kheops. The Report Provider MUST verify the value the return_uri to prevent it being used as an open redirector.
studyUID: The Study Instance UID of the study for which a report is to be generated. Will appear once for each study selected if study_multiplicity is 'multiple', or not at all if study_multiplicity is 'all'.

To prevent token substitution attacks, the Report Provider should use the introspection_endpoint to validate that the redirect_uri associated with the Access Token matches the called URL.

Example

Line breaks for display purposes only.

https://reportprovider.kheops.online/report.html#access_token=ey...DUszcU
&token_type=bearer&expires_in=3600&scope=read%20write
&conf_uri=https%3A%2F%2Fdemo.kheops.online%2F.well-known%2Freport-provider-configuration
&client_id=Ya7IHXuubSsv9PJy9GXifx
&return_uri:"https%3A%2F%2Fdemo.kheops.online%2Falbums%2FM1qJb98LJe"  
&studyUID=1.3.6.1.4.1.5962.1.2.0.1175775772.5729.0

Authorization Code (code) flow

When the user activates the Report Provider, the user will be redirected to the redirect_uri with the following additional query parameters.

code: The Authorization Code.
conf_uri: URL string that points to the configuration of the Report Provider on the Kheops instance.
client_id: The client ID of the Report Provider on the Kheops instance.
return_uri: URL to which to send the user when returning the user's user agent to Kheops. The Report Provider MUST verify the value the return_uri to prevent it being used as an open redirector.
studyUID: The Study Instance UID of the study for which a report is to be generated. Will appear once for each study selected if study_multiplicity is 'multiple', or not at all if study_multiplicity is 'all'.

Example

Extra line breaks for display purposes only.

https://reportprovider.kheops.online/report.html?code=ey...DUszcU
&conf_uri= https%3A%2F%2Fdemo.kheops.online%2F.well-known%2Freport-provider-configuration
&client_id=Ya7IHXuubSsv9PJy9GXifx
&return_uri:"https%3A%2F%2Fdemo.kheops.online%2Falbums%2FM1qJb98LJe"  
&studyUID=1.3.6.1.4.1.5962.1.2.0.1175775772.5729.0

Obtaining an Access Token with the Authorization Code flow

To obtain an Access Token from an Authorization Code, the Report Provider needs to call the token_endpoint with proper authorization. Currently the only authorization method supported for Report Providers is the private_key_jwt method.

The following parameters must be sent to the token_endpoint using the application/x-www-form-urlencoded content-type.

grant_type: Must be authorization_code.
code: The Authorization Code obtained as a query parameter.
client_id: The client ID obtained as a query parameter.
client_assertion_type: Must be set to urn:ietf:params:oauth:client-assertion-type:jwt-bearer.
client_assertion: The private_key_jwt signed using a private key that corresponds to a public key made available through the jwks_uri parameter returned by the Configuration URL.
redirect_uri: Must be identical to the redirect_uri parameter returned by the Configuration URL.

Example

Sample call to the token_endpoint.

Extra line breaks for display purposes only.

POST /api/token HTTP/1.1
Host: demo.kheops.online
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=ey...DUszcU&client_id=Ya7IHXuubSsv9PJy9GXifx
&redirect_uri=https%3A%2F%2Freportprovider.kheops.online%2Freport.html
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=ey...fjGFT

Sample response.

HTTP/1.1 200 OK
Content-Type: application/json

{
    "access_token": "eyJ0e...r90EZTAU",
    "token_type": "bearer",
    "expires_in": 3600
}

Signing a private_key_jwt

The private_key_jwt is a JWT signed using a private key that corresponds to a public key made available through the jwks_uri parameter returned by the Configuration URL. The JWT must have the following claims.

iss: REQUIRED. Issuer. This must contain the client ID of the Report Provider.
sub: REQUIRED. Subject. This must contain the client ID of the Report Provider.
aud: REQUIRED. Audience. This must be the URL String of the endpoint the private_key_jwt is being used to authenticating with.
jti: REQUIRED. JWT ID. A unique identifier for the token, which can be used to prevent reuse of the token.
exp: REQUIRED. Expiration time on or after which the ID Token will not be accepted for processing. The expiration time can not be more than 10 minutes in the future.
iat: OPTIONAL. Time at which the JWT was issued.

Example

Decoded JWT

{
    "typ": "JWT",
    "alg": "RS256"
    "kid": "0"
}
{
    "iss": "Ya7IHXuubSsv9PJy9GXifx",
    "sub": "Ya7IHXuubSsv9PJy9GXifx",
    "aud": "https://demo.kheops.online/api/token",
    "jti": 1001,
    "exp": 1560964511,
    "iat": 1560960911
}

conf_uri

The conf_uri is a URL string provided either as a query parameter (Authorization Code flow), or as a fragment parameter (Implicit flow) when redirecting to the redirect_uri. It will point to a JSON object with the following parameters.

issuer: The value set as the iss claim of JWTs signed by the Kheops instance.
dicomweb_endpoint: URL string for DICOMweb WADO-RS, QIDO-RS and STOW-RS.
dicomweb_uri_endpoint: URL string for DICOMweb WADO-URI.
token_endpoint: URL string for the token endpoint.
introspection_endpoint: URL string for the introspection endpoint.
userinfo_endpoint: URL string for the userinfo endpoint.
grant_types_supported: Array of available grant types.
token_endpoint_auth_methods_supported: Authentication methods supported at the token endpoint.
token_endpoint_auth_signing_alg_values_supported: Cryptographic algorithms supported for authentication at the token endpoint.
introspection_endpoint_auth_methods_supported: Authentication methods supported at the introspection endpoint.
introspection_endpoint_auth_signing_alg_values_supported: Cryptographic algorithms supported for authentication at the introspection endpoint.
response_types_supported: Supported response types. `response_modes_supported": Supported response modes.

Example

HTTP/1.1 200 OK
Content-Type: application/json

{
    "issuer": "https://demo.kheops.online",
    "dicomweb_endpoint": "https://demo.kheops.online/api",
    "dicomweb_uri_endpoint": "https://demo.kheops.online/api/wado",
    "token_endpoint": "https://demo.kheops.online/api/token",
    "introspection_endpoint": "https://demo.kheops.online/api/token/introspect",
    "userinfo_endpoint": "https://demo.kheops.online/api/userinfo",
    "grant_types_supported": ["authorization_code", "implicit"],
    "token_endpoint_auth_methods_supported": ["private_key_jwt"],
    "token_endpoint_auth_signing_alg_values_supported": ["RS256"],
    "introspection_endpoint_auth_methods_supported": ["private_key_jwt", "none"],
    "introspection_endpoint_auth_signing_alg_values_supported": ["RS256"],
    "response_types_supported": ["code", "token"],
    "response_modes_supported": ["query", "fragment"]
}

Access Token Introspection

Report Providers can call the introspection_endpoint to find if an Access Token is valid or not. Implicit (token) flow Report Providers should use the introspection endpoint to verify the redirect_uri of the provided Access Token to guard against token substitution attacks. Implicit flow (token) Report Providers do not need to authenticate to the introspection_endpoint.

The following parameter must be sent to the introspection_endpoint using the application/x-www-form-urlencoded content-type.

token: The Access Token to be inspected.

The introspection_endpoint will return a JSON object with the following values.

active: True if the token is valid. False otherwise. If False, no other information is returned.
iss: Issuer. Identifies the Kheops instance that issued the Access Token.
sub: Subject. Identifies the user who initiated the transaction with the Report Provider.
aud: Audience. Identifies the Kheops instance at which the Access Token is meant to be used. This may be an array of string is there are multiple audiences.
exp: Expiration Time. The time expressed in "Seconds Since the Epoch" at which the Access Token will no longer be valid.
iat: Issued At. The time when the Access Token was issued expressed in "Seconds Since the Epoch".
nbf: Not Before. The time expressed in "Seconds Since the Epoch" at which the Access Token will begin to be valid.
redirect_uri: The redirect_uri for the Report Provider for which this Access Token was issued.
azp: Authorized Party. The client ID of the Report Provider.
client_id: The client ID of the Report Provider.
scope: Scope of the Access Token. For example 'read' or 'read write'.
studyUID: The Study Instance UID that the Report Provider was requested to work on. May be an array if the Report Provider was requested to work on multiple studies. Will be absent if 'study_multiplicity' is set to all.
album_id: OPTIONAL On KHEOPS, the album ID of the album the Report Provider is attached to.

Example

Sample call to the introspection_endpoint.

POST /api/token/introspect HTTP/1.1
Host: demo.kheops.online
Content-Type: application/x-www-form-urlencoded

token=ey...DUszcU

Sample response.

HTTP/1.1 200 OK
Content-Type: application/json

{
    "active": true,
    "iss": "https://demo.kheops.online",
    "sub": "9a1d2d5d-30af-4d06-851f-54d705ade65a",
    "aud": "https://demo.kheops.online",
    "exp": 1561226205,
    "iat": 1561222605,
    "nbf": 1561222605,
    "redirect_uri": "https://reportprovider.kheops.online/report.html",
    "azp": "Ya7IHXuubSsv9PJy9GXifx",
    "client_id": "Ya7IHXuubSsv9PJy9GXifx",  
    "album_id": "w0QzsXub6f",
    "scope": "read write",
    "studyUID": "2.16.840.1.113669.632.20.121711.10000158860"
}

UserInfo

The userinfo_endpoint can be used to get identifying information about the user who activated the Report Provider. It is an OAuth2.0 Protected Resource that returns the following parameters.

sub: Subject. Identifies the user who initiated the transaction with the Report Provider.
name: The name of the user.
given_name: The given name of the user.
family_name: The family name of the user.
email: The email address of the user.
preferred_username: The username of the user.

Example

Sample call to the userinfo_endpoint.

GET api/userinfo HTTP/1.1
Host: demo.kheops.online
Authorization: Bearer ey...DUszcU

Sample response.

HTTP/1.1 200 OK
Content-Type: application/json

{
    "sub": "9a1d2d5d-30af-4d06-851f-54d705ade65a",
    "name": "Joël Spaltenstein",
    "given_name": "Joël",
    "family_name": "Spaltenstein",
    "email": "spalte@naturalimage.ch",
    "preferred_username": "spalte"
}

Security Considerations

While it is currently possible to register a Report Provider with Kheops that uses non-secure http connections, this is unacceptable for systems that transmit data that is not already publicly available, and is only currently enabled to ease the development of Report Providers.

Report Providers that deal with sensitive data must not promiscuously accept data from any Kheops instance. Report Providers can use the host of the conf_uri to ensure that they are in fact dealing with expected instances of Kheops.

Given that the Report Provider API is largely based on OAuth 2.0, developers should become familiar with the OAuth 2.0 Security Considerations, the OAuth 2.0 Threat Model and Security Considerations, and the draft OAuth 2.0 Security Best Current Practice.

The Following items are also of interest:

A major difference between the OpenID Connect/OAuth 2.0 and the Report Provider API is that with the former it is the Client (Report Provider) which initiates the connection, whereas in the later it is the Authorization Server (Kheops instance) which initiates the connection. This has several implications, amongst the most important of which is that the OAuth 2.0 strategy to defend against CSRF attacks by including a state parameter when initiating an authorization request is not possible. For this reason, Report Providers must find other means to secure their redirect_uri against CSRF attacks.

Clone this wiki locally