JS client configuration

569 views
Skip to first unread message

Julien Delafontaine

unread,
Jan 19, 2017, 12:57:09 PM1/19/17
to SMART on FHIR
Hello,

I am building a Javascript client to ultimately access data from our own private, future OAuth2 protected server.
First I'd like to share the experience of a brand new user, hoping this will be useful for you.
I am stuck at the end of this process:

1. I started with the FHIR/fhir.js GitHub project, but could never understand how to set that up from the docs, in particular what that "adapter" was.

2. I decided to take inspiration from a working project, so I went to the cardiac-risk-app source code and discovered this smart-on-fhir/client-js project - that uses the one above.

3. From the client-js docs, we are redirected to the "Clients/Javascript" docs page, that says we should use `FHIR.oauth2.ready()` with a callback, which is what the cardiac-risk-app uses, although it did nothing in my case (with a console.debug print in the callback). I it supposed to?

4. Fortunately, this same page links to the "Tutorial - Building a JavaScript App" docs page, which illustrates the use of `FHIR.client({ <config> })`, although it writes "In a typical workflow, you won’t instantiate this object yourself – it will be created by `FHIR.oauth2.launch()`". But
* There is no indication of how to write a full <config> for authentication;
* "FHIR.oauth2.launch() is not a function";
* `FHIR.oauth2.authorize({...})` says "str is undefined", because the real error (missing URL arguments) is not caught.

5. Using `FHIR.client({serviceUrl: 'https://fhir-open-api-dstu2.smarthealthit.org'})`, I could execute a request to this test server and read the response successfully.

So with that I read the "10 mL bid" medication for example patient 103888 or whatever from the test server.

At this point I am stuck. I don't know where to find docs to configure the client for my own FHIR server without deciphering the source code of client-js; I don't know what FHIR.method (.ready, .authorize, .launch, .client - are some of them calling the others?) I should use to start and how.

Am I even supposed to bother about Autorization, if the description for tutorial "Simple Authorization App" says "If you would rather start with writing SMART on FHIR apps as quickly as possible, you can use our client libraries which handle the authorization process for you."? At some point, I will have to choose which type of OAuth workflow I want to use, and enter some configuration for it.

Please give me a clue for the next step.


Pascal Brandt

unread,
Jan 19, 2017, 3:30:25 PM1/19/17
to Julien Delafontaine, SMART on FHIR
Hi Julien,

I'm not sure if this the right list to get support for creating an OAuth2 provider or FHIR server, but I can respond to some of the JS client questions.

3. From the client-js docs, we are redirected to the "Clients/Javascript" docs page, that says we should use `FHIR.oauth2.ready()` with a callback, which is what the cardiac-risk-app uses, although it did nothing in my case (with a console.debug print in the callback). I it supposed to?

Yes, absolutely. Once the authorization workflow is completed, this is how you invoke your application (toy example). These docs do a good job of explaining this workflow, and I guess you already found this JavaScript client tutorial. How are you launching your application? Is your launch URL being invoked and successfully redirecting to your application URL? Is your code available somewhere to look at?

5. Using `FHIR.client({serviceUrl: 'https://fhir-open-api-dstu2.smarthealthit.org'})`, I could execute a request to this test server and read the response successfully.

I guess because this is an unprotected server that doesn't require OAuth2 authentication? To test your authorization workflow code, I recommend use the SMART or Epic sandboxes.

Cheers,
Pascal


--
You received this message because you are subscribed to the Google Groups "SMART on FHIR" group.
To unsubscribe from this group and stop receiving emails from it, send an email to smart-on-fhir+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nikolai Schwertner

unread,
Jan 19, 2017, 4:18:00 PM1/19/17
to smart-...@googlegroups.com
Hi Julien,

The piece that you seem to be missing here is that a SMART app (which needs to do the OAuth2 handshake) will be provided the FHIR endpoint as a parameter on its launch endpoint. You should not need to hardcode this URL into your app. Take a look at this sample app for usage example of the client library:
https://github.com/smart-on-fhir/sample-apps/tree/master/simple-app

Also, worth noting that the running examples on the documentation site (in JSFiddle etc) circumvent authentication by going directly to the open API server and are therefore not "real" SMART apps.

Regards,
Nikolai
--
You received this message because you are subscribed to the Google Groups "SMART on FHIR" group.
To unsubscribe from this group and stop receiving emails from it, send an email to smart-on-fhi...@googlegroups.com.

Pascal Pfiffner

unread,
Jan 20, 2017, 2:25:30 AM1/20/17
to SMART on FHIR
I think what Julien is asking is how do you configure the JS app to which SMART on FHIR endpoint to connect to in the first place. This is not obvious from the simple-app example because it is not documented and nowhere in the code is a FHIR endpoint specified. The sample app could use a short README that explains how the app is launched.

Julien, all these JS apps are designed to go through the "traditional" launch sequence, meaning they are launched from an EHR or similar and receive the FHIR endpoint they should connect to as the iss URL parameter. The JS-client extracts that URL and starts the OAuth dance, hence there's no need to configure it manually. See here:

Remember, SMART discerns between such an EHR launch and a standalone launch.

Nikolai, how would you use the JS client in a (protected) standalone launch?

Cheers,
Pascal

Julien Delafontaine

unread,
Jan 20, 2017, 5:56:58 AM1/20/17
to SMART on FHIR
Thank you all for your answers, that helps a lot.

I had the Standalone launch sequence in mind indeed (more intuitive), and the only difference I see between launch sequences is the way the FHIR base URL+scope is provided, so why not hard-coding it if it is constant anyway?
To me, starting from an EHR session should just mean something comparable to "you are already logged in to your google account, so we can skip the google login step" when you use one of these "Log in with google" buttons.

Now suppose I do it Standalone, when the server is protected, instantiating "FHIR.client()" directly requires hard-coding the auth token, which is not possible. On the other hand, calling "FHIR.oauth2.authorize()" won't do anything without knowing the FHIR base URL. I am confused.

So Pascal is correct correct, my question is in fact "how would you use the JS client in a (protected) standalone launch?"

A README in the simple-app would be helpful, too (like how you registered it (launch URL, redirect URL) and how it is launched).

Julien

Pascal Pfiffner

unread,
Jan 21, 2017, 5:16:23 AM1/21/17
to SMART on FHIR
There is no need to hardcode the base URL into the app when you use an EHR launch because it's provided by the EHR. This way, one and the same installation of an app, e.g. app.awesome.io , can be used from different EHRs/FHIR servers.

On the other hand, for a standalone launch you can either just hardcode the base URL or you can let a user choose or even enter the base URL of the FHIR server to connect to. How you pass that URL into the client when using FHIR.oauth2 .authorize() I'm not sure as I haven't used the JS client myself. Nikolai should be able to answer that.

Pascal

Nikolai Schwertner

unread,
Jan 21, 2017, 1:50:37 PM1/21/17
to smart-...@googlegroups.com
Ok, I see now what you mean. We do have an example of how to do this
with the JS client. Take a look at this app:

https://github.com/smart-on-fhir/sample-apps/tree/master/authorize-client

The most relevant part of the code is
https://github.com/smart-on-fhir/sample-apps/blob/master/authorize-client/app.js#L77-L84
where we demonstrate how to trigger the authorization process against a
specific server. For standalone apps, what you'd want to do is not
specify a "launch" parameter and request a "launch/patient" scope. Such
as in:

https://github.com/smart-on-fhir/sample-apps/tree/master/standalone

If you combine the code from these two apps (setting up the fhir
endpoint and requesting the "launch/patient" scope), I think you will
have all that you need.

Hope this helps

Nikolai

Nikolai Schwertner

unread,
Jan 21, 2017, 2:24:10 PM1/21/17
to smart-...@googlegroups.com
Actually, here, I updated the example so that it does not need the "iss"
parameter any longer:
https://github.com/smart-on-fhir/sample-apps/commit/f244b5

Julien Delafontaine

unread,
Jan 25, 2017, 8:55:07 AM1/25/17
to SMART on FHIR
Thanks it worked!!

If by any chance it makes it clearer for somebody else:

- I registered my app with your online form (http://docs.smarthealthit.org/sandbox/register/) to get my Client ID;
  I put `localhost:3000/launch` as launch URI, and `localhost:3000/home` as redirect URI.
- I added a route /launch (localhost:3000/launch) that calls `FHIR.oauth2.authorize()` as above, with my new Client ID. I removed the "launch/patient" part from "scope" from the example (otherwise it will launch some other app where you have to select a patient);
- When I hit /launch, it redirects me to OpenID Connect server login, and I log in;
- It asks if I want to authorize my app to read stuff, which I allow;
- I am redirected to my own app (localhost:3000/home), which has been waiting for that to execute the callback associated to `FHIR.oauth2.ready()`.

With React, call `ready()` before anything else, and make the callback save the `FHIR` object in the store. Make the Launch component call `authorize()`, and when redirected, other components can use the `FHIR` object from the store.

Julien Delafontaine

unread,
Jan 25, 2017, 9:25:20 AM1/25/17
to SMART on FHIR
I was too quick... I cannot see any data from https://fhir-api-dstu2.smarthealthit.org.
When I `.search`, I only get empty bundles:

    {
      "resourceType": "Bundle",
      "type": "searchset",
      "total": 0,
      "link": [
        {
          "relation": "self",
          "url": "https://fhir-api-dstu2.smarthealthit.org/Patient?name=a"
        }
      ]
    }

And when I request a particular ID, it tells me that I am not authorized:

    FHIR.oauth2.ready(function(smart){
        smart.api.read({type: 'Patient', id: '99912345'})
    });

> "Unauthorized:  Need any one of [Patient/99912345] but you only have []"
> fhir-client.js:15664 GET https://fhir-api-dstu2.smarthealthit.org/Patient/99912345 - 401 (Unauthorized)

There is a Bearer token in the request.
What did I miss?

Julien Delafontaine

unread,
Jan 25, 2017, 11:05:54 AM1/25/17
to SMART on FHIR
All right it works now with this scope:

  "scope": "user/*.read"

Nikolai Schwertner

unread,
Jan 25, 2017, 6:05:30 PM1/25/17
to smart-...@googlegroups.com
Glad to hear that it is working now.
--

Julien Delafontaine

unread,
Jan 26, 2017, 4:21:53 AM1/26/17
to SMART on FHIR
Why is there nothing in localStorage after I get authorization to query data from the FHIR server? I expected to find a JWT there, and be able to "log out" by deleting it. Are you using cookies instead?

Also I am surprised that I never had to use the "Registration access token" anywhere after registration.

Pascal Pfiffner

unread,
Jan 26, 2017, 4:53:59 AM1/26/17
to SMART on FHIR
I don't know the answer to the first question, but the registration access token is only needed to change your client configuration via the portal – this token gives you access to your client settings on the server, it's not needed client-side.

Pascal

Pascal Pfiffner

unread,
Jan 26, 2017, 4:56:06 AM1/26/17
to SMART on FHIR
p.s.
For clarification how "scopes" work, see here:
Reply all
Reply to author
Forward
0 new messages