OHIF + Orthanc: token to access a single study

Hi everyone,

First a disclaimer: I’m quite a newbie in OHIF but I’m one of the Orthanc maintainer. I’m trying to integrate OHIF with Orthanc in order to grant access to a single study (or clearly identified multiple studies).

We have everything we need in Orthanc to grant access to a single study based on a token - the first challenge here is to configure OHIF (v3-stable) such that it includes this token in every HTTP request to orthanc. We have already done this for other more Orthanc centric viewers (like the Stone Web Viewer).

Typically, I’d like to open OHIF with this kind of url: http://localhost/viewer?StudyInstanceUIDS=1.2.3&token=my-token and have an HTTP Header "token": "my-token" included in every request.

What I’ve tried so far:

  • I played with the requestOptions configuration (I could generate a config file dynamically if needed) but I could not even make it work with basic auth. Is there a full sample available to demonstrate how to use requestOptions possibly with Orthanc ?
  • I modified OHIF to take this token from the URL arguments: it worked partially but, some requests are sent from the cornerstone-wado-image-loader and I did not want to start modifying dependencies
  • I made a small redirect page that adds the token in the cookies and a reverse proxy that reads the token from cookie to add it back to the headers.

This last attempt is working in terms of the token being received by Orthanc. However, I’m encountering another problem: OHIF makes a QIDO-RS call to list studies based on the PatientID (http://localhost:81/orthanc/dicom-web/studies?00100020=*108506*&limit=101&offset=0&fuzzymatching=false&includefield=00081030%2C00080060).
Since my token grants access to a single study, my authorization layer forbids this call that could return data from other patients whose PatientID would match the *PatientID* filter.
Therefore OHIF receives a 403. One of the impact is that the series thumbnail is not displayed in this case !

Hence my last question: is there a way to:

  • prevent OHIF to perform that QIDO-RS query that seems to search for prior studies
  • make OHIF more strict and look for exact match of the PatientID (in this case, I could use tokens that would grant access to a full patient and not a single study)

Thanks a lot for your help, that would help both communities a lot !

Alain Mazy


Bumping. we would love to see this resolved as OHIF is our production viewer and we would really like to upgrade Orthanc to implement the new study sharing functionality.

Hi Alain,

I’m doing some customizations on OHIF and found the code responsible for QIDO-RS query:



async function fetchStudiesForPatient(StudyInstanceUID) {
const qidoStudiesForPatient =
(await getStudiesForPatientByStudyInstanceUID(StudyInstanceUID)) || ;

  // TODO: This should be "naturalized DICOM JSON" studies
  const mappedStudies = _mapDataSourceStudies(qidoStudiesForPatient);

  const actuallyMappedStudies = mappedStudies.map(qidoStudy => {
    return {
      studyInstanceUid: qidoStudy.StudyInstanceUID,
      date: formatDate(qidoStudy.StudyDate),
      time: qidoStudy.StudyTime,
      description: qidoStudy.StudyDescription,
      modalities: qidoStudy.ModalitiesInStudy,
      numInstances: qidoStudy.NumInstances,
      // displaySets: []




async function getStudiesForPatientByStudyInstanceUID(
) {
if (StudyInstanceUID === undefined) {
// TODO: The DicomMetadataStore should short-circuit both of these requests
// Data could be here from route query, or if using JSON data source
// We could also force this to “await” these values being available in the DICOMStore?
// Kind of like promise fulfillment in @cornerstonejs/dicom-image-loader when there are multiple
// outgoing requests for the same data
const getStudyResult = await dataSource.query.studies.search({
studyInstanceUid: StudyInstanceUID,

// TODO: To Erik’s point, the data source likely shouldn’t deviate from
// Naturalized DICOM JSON when returning. It makes things like this awkward (mrn)
if (getStudyResult && getStudyResult.length && getStudyResult[0].mrn) {
return dataSource.query.studies.search({
patientId: getStudyResult[0].mrn,
console.log(‘No mrn found for’, getStudyResult);
// The original study we KNOW belongs to the same set, so just return it
return getStudyResult;

export default getStudiesForPatientByStudyInstanceUID;


As for your last request (making OHIF look for exact match of PatientID). I think it should be be as simple as modifying this line of code from extensions/default/src/DicomWebDataSource/qido.js 177:
‘00100020’: withWildcard(params.patientId),
to this:
‘00100020’: params.patientId

I am willing to work on this if you could give me some guidance.

Hi @egregiousviolations

Thanks for your investigation.

I had a call yesterday with @alireza from the OHIF team and he was planning to look at this issue one of these days. So I’ll wait for his feedback before going any further.

Thanks again !


FYI, this has now been fixed in this commit feat(panel and auth): fix study panel to not rely on priors and add token param to url by sedghi · Pull Request #3381 · OHIF/Viewers · GitHub thanks to @alireza


hello thanks for all you do.

just a quick folllow up on the previous issues raised by @alainmazy, on intergrating ohif with orthanc explorer 2, the ohif runs perfectly well on localhost with orthanc explorer 2. but however once switched to a numeric ip address for remote connection it returns a blank screen as seen in the image below.
here is the docker compose file .

Same for me when using nginx as a proxy with this error

decodeImageFrame.ts:266 Uncaught (in promise) ReferenceError: SharedArrayBuffer is not defined
at decodeImageFrame.ts:266:51
at U (decodeImageFrame.ts:154:25)
at async Object.handler (decodeTask.ts:51:9)

hello @edcheyjr

i think sharedArraybuffer must be enabled. i read something like that in a post here.

Okay thanks, i look at it

check at this kuna some docker image hapo had i think they are using keycloak

Welcome to the community @holakunle69. I don’t think you actually included the docker compose file. Could you please do so? Thanks.

@edcheyjr , this is likely related to certain response headers not being set in your server. Have a look at the following links for more info…

Hope this helps.

1 Like

thanks @jbocce

here is the docker compose file as well as the response from the browser.

version: “3”

image: orthancteam/orthanc-nginx:23.5.0
depends_on: [orthanc, orthanc-auth-service, keycloak]
restart: unless-stopped
ports: [“80:80”]

if setting ENABLE_HTTPS: “true” env var, uncomment the following 4 lines and comment the line with ‘ports: [“80:80”]’

ports: [“443:443”]


- /…/crt.pem:/etc/nginx/tls/crt.pem

- /…/key.pem:/etc/nginx/tls/key.pem

  ENABLE_HTTPS: "false"
  ENABLE_OHIF: "true"

image: osimis/orthanc:23.5.0
- orthanc-storage:/var/lib/orthanc/db
depends_on: [orthanc-db]
restart: unless-stopped
“Name”: “Orthanc”,
“OrthancExplorer2”: {
“IsDefaultUI”: true,
“UiOptions”: {
“EnableShares”: true,
“DefaultShareDuration”: 0,
“ShareDurations”: [0, 7, 15, 30, 90, 365],
“EnableOpenInOhifViewer3”: true,
“OhifViewer3PublicRoot”: “
“Tokens” : {
“InstantLinksValidity”: 3600,
“ShareType”: “stone-viewer-publication”
“Keycloak” : {
“Enable”: true,
“Url”: “”,
“Realm”: “orthanc”,
“ClientId”: “orthanc”
“AuthenticationEnabled”: false, // because it is handled by the authorization plugin
“Authorization”: {
“WebServiceRootUrl”: “http://orthanc-auth-service:8000/”,
“WebServiceUsername”: “share-user”,
“WebServicePassword”: “change-me”,
“StandardConfigurations” : [
“CheckedLevel”: “studies”
“DicomWeb”: {
“Enable”: true,
“PublicRoot”: “/orthanc/dicom-web/”

image: orthancteam/orthanc-auth-service:23.5.0
depends_on: [keycloak]
restart: unless-stopped
SECRET_KEY: “change-me-I-am-a-secret-key”
“share-user”: “change-me”

image: postgres:14
restart: unless-stopped
volumes: [“orthanc-db:/var/lib/postgresql/data”]

image: orthancteam/ohif-v3:main
restart: unless-stopped

image: orthancteam/orthanc-keycloak:23.5.0
depends_on: [keycloak-db]
restart: unless-stopped
KC_DB: “postgres”
KC_DB_URL: “jdbc:postgresql://keycloak-db:5432/keycloak”
KC_DB_USERNAME: “keycloak”
KC_DB_PASSWORD: “keycloak”

image: postgres:14
restart: unless-stopped
volumes: [“keycloak-db:/var/lib/postgresql/data”]
POSTGRES_USER: “keycloak”
POSTGRES_DB: “keycloak”


Try running the OHIF server over https since SharedArrayBuffer needs a secure context.

1 Like

thanks @jbocce

i pulled a branch of ohif viewer-v3 from git. i want to remove the preloaded studies. how do i go about this.

@holakunle69, just for clarification, the preloaded studies you speak of are NOT part of the code which you cloned and checked out. They are remote resources fetched from the default data source that is configured in the default config file.

As such to “remove” the preloaded studies, simply replace the config file used with your own OR replace the data sources in the default config file.

I hope this helps.

1 Like

I’m interested in one of Alain’s original questions, that I think wasn’t (or just partially) answered :

[can we] prevent OHIF to perform that QIDO-RS query that seems to search for prior studies ?

In our setup (custom authorization with Orthanc, similar to what Alain described), we want the client using OHIF to only be able to see the single study in the viewer identified by the StudyInstanceUID of the URL and not see any other studies of the same patient.

Looking at the fix by @alireza , as I understand, this try-catch block is meant to take care of the case when the server can’t handle the request: feat(panel and auth): fix study panel to not rely on priors and add token param to url by sedghi · Pull Request #3381 · OHIF/Viewers · GitHub

Now in our case, Orthanc does handle it, but our custom authorization denies the response with a 403, which means we get “red” stuff in the browser console / network tab.
It would be better if we could disable those requests altogether. Is there a way to do that by configuration? It seems to be a “static” part of the “Basic Viewer” mode. Could we add a configuration option for that?

Thank you for your help!