-
Notifications
You must be signed in to change notification settings - Fork 37
/
Copy pathconfidential-smart-ehr-launch.js
128 lines (107 loc) · 3.82 KB
/
confidential-smart-ehr-launch.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */
/* eslint no-console: 0, import/no-unresolved: 0 */
const express = require('express');
const session = require('express-session');
const simpleOauthModule = require('simple-oauth2');
const Client = require('../../lib/client');
const CLIENT_ID = '<CLIENT_ID>';
const CLIENT_SECRET = '<CLIENT_SECRET>';
const app = express();
// Use session to pass the iss information to the callback
app.use(session({
secret: 'keyboard cat',
cookie: { maxAge: 60000 },
resave: true,
saveUninitialized: true,
}));
/**
* This is an example of a SMART app launching from within an EHR.
*
* In this example, there are two routes:
* - /launch
* - /callback
*
* The EHR will call the launch route with two parameters: iss and launch. The
* SMART app will make a request to the OAuth server's authorization URL.
* Then, it will redirect to the SMART app callback.
*
* In the callback route, another request is made (using the simple-oauth
* library) to request a token from the OAuth2 server. The server will then
* send back a launch_context containing, among other things, an access token to
* set in the Authorization header and use for subsequent FHIR requests (to the
* ISS).
*/
app.get('/launch', async (req, res) => {
const { iss, launch } = req.query;
const fhirClient = new Client({ baseUrl: iss });
const { authorizeUrl, tokenUrl } = await fhirClient.smartAuthMetadata();
req.session.iss = iss;
// Create a new oAuth2 object using the Client capability statement:
const oauth2 = simpleOauthModule.create({
client: {
id: CLIENT_ID,
secret: CLIENT_SECRET,
},
auth: {
tokenHost: `${tokenUrl.protocol}//${tokenUrl.host}`,
tokenPath: tokenUrl.pathname,
authorizeHost: `${authorizeUrl.protocol}//${authorizeUrl.host}`,
authorizePath: authorizeUrl.pathname,
},
options: {
authorizationMethod: 'body',
},
});
// Authorization uri definition
const authorizationUri = oauth2.authorizationCode.authorizeURL({
redirect_uri: 'http://localhost:3000/callback',
launch,
aud: iss,
scope: 'launch openid profile user/Patient.read',
state: '3(#0/!~',
});
res.redirect(authorizationUri);
});
// Callback service parsing the authorization token and asking for the access token
app.get('/callback', async (req, res) => {
const { iss } = req.session;
console.log(req.session);
const fhirClient = new Client({ baseUrl: iss });
const { authorizeUrl, tokenUrl } = await fhirClient.smartAuthMetadata();
// Create a new oAuth2 object using the Client capability statement:
const oauth2 = simpleOauthModule.create({
client: {
id: CLIENT_ID,
secret: CLIENT_SECRET,
},
auth: {
tokenHost: `${tokenUrl.protocol}//${tokenUrl.host}`,
tokenPath: tokenUrl.pathname,
authorizeHost: `${authorizeUrl.protocol}//${authorizeUrl.host}`,
authorizePath: authorizeUrl.pathname,
},
options: {
authorizationMethod: 'body',
},
});
const { code } = req.query;
const options = {
code,
redirect_uri: 'http://localhost:3000/callback',
};
try {
const result = await oauth2.authorizationCode.getToken(options);
const { token } = oauth2.accessToken.create(result);
console.log('The token is : ', token);
fhirClient.bearerToken = token.access_token;
const patient = await fhirClient.read({ resourceType: 'Patient', id: token.patient });
return res.status(200).json(patient);
} catch (error) {
console.error('Access Token Error', error.message);
return res.status(500).json('Authentication failed');
}
});
const server = app.listen(3000, 'localhost', () => {
console.log('Express server started on port 3000');
console.log(`SMART Launch endpoint is at http://${server.address().address}:3000/launch`);
});