-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquickstart.js
146 lines (116 loc) · 5.21 KB
/
quickstart.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
require('dotenv').config();
const jwt = require('jsonwebtoken');
const util = require('util');
const querystring = require('querystring');
const { v4: uuidv4 } = require('uuid');
// **NOTE!** In a real production app you would want these to be sourced from real environment variables. The .env file is just
// a convenience for development.
const rksProjectId = process.env.RKS_PROJECT_ID;
const rksServiceAccount = process.env.RKS_SERVICE_ACCOUNT;
const privateKey = process.env.RKS_PRIVATE_KEY;
const baseUrl = 'https://designer.mydatahelps.org';
const tokenUrl = `${baseUrl}/identityserver/connect/token`;
async function getServiceAccessToken() {
const assertion = {
"iss": rksServiceAccount,
"sub": rksServiceAccount,
"aud": tokenUrl,
"exp": Math.floor(new Date().getTime() / 1000) + 200,
"jti": uuidv4()
};
var signedAssertion;
try {
signedAssertion = jwt.sign(assertion, privateKey, { algorithm: 'RS256' });
}
catch(err) {
console.log(`Error signing JWT. Check your private key. Error: ${err}`);
return null;
}
const payload = {
scope: "api",
grant_type: "client_credentials",
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
client_assertion: signedAssertion
};
const response = await fetch(tokenUrl, { method: "POST", headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: querystring.stringify(payload) });
if (!response.ok) {
const error = `Get service access token failed. ${response.status} - ${await response.text()}`;
throw new Error(error);
}
const data = await response.json();
return data.access_token;
}
async function getFromApi(serviceAccessToken, resourceUrl, queryParams = null, raiseError = true) {
const queryString = queryParams ? `?${new URLSearchParams(queryParams)}` : '';
const url = `${baseUrl}${resourceUrl}${queryString}`;
const response = await fetch(url, {
headers: {
"Authorization": `Bearer ${serviceAccessToken}`,
"Accept": "application/json",
"Content-Type": "application/json; charset=utf-8"
}
});
if (!response.ok && raiseError) {
const error = `API call to ${url} failed. ${response.status} - ${await response.text()}`;
throw new Error(error);
}
return { data: await response.json(), status: response.status };
}
// Get a participant access token for the specified participant
// Used for MyDataHelps Embeddables ONLY
async function getParticipantAccessToken(serviceAccessToken, participantID, scopes) {
const payload = {
"scope": scopes,
"grant_type": "delegated_participant",
"participant_id": participantID,
"client_id": "MyDataHelps.DelegatedParticipant",
"client_secret": "secret",
"token": serviceAccessToken,
}
const response = await fetch(tokenUrl, { method: "POST", headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: querystring.stringify(payload) });
if (!response.ok) {
const error = `Get participant access token failed. ${response.status} - ${await response.text()}`;
throw new Error(error);
}
const data = await response.json();
return data.access_token;
}
// Use this utility if you ever need to print a response for debugging
function logResponse(response) {
console.log(util.inspect(response, { colors: true, depth: 3 }));
}
async function quickstart() {
var url;
var response;
// Get a service access token, needed for all API calls.
const serviceAccessToken = await getServiceAccessToken();
console.log('Obtained service access token:');
console.log(serviceAccessToken);
// Get all participants
url = `/api/v1/administration/projects/${rksProjectId}/participants`;
response = await getFromApi(serviceAccessToken, url);
const participants = response.data;
console.log(`\nTotal Participants: ${participants.totalParticipants}`);
// Get a specific participant by identifier. We disable 'raiseError' here
// so we can handle the 404 case ourselves.
const participantIdentifier = "YOUR_PARTICIPANT_IDENTIFIER"
if (participantIdentifier != "YOUR_PARTICIPANT_IDENTIFIER") {
url = `/api/v1/administration/projects/${rksProjectId}/participants/${participantIdentifier}`;
response = await getFromApi(serviceAccessToken, url, null, false );
if (response.status === 404) {
console.log("\nParticipant not found.");
} else {
const participant = response.data;
console.log(`\nParticipant Found. ID: ${participant.id}`);
// NOTE: This piece is only necessary when using MyDataHelps Embeddables in a custom app.
// Most API use cases do NOT require a participant token.
// Be sure to:
// 1. Use the internal ID field (from participant.id above) and NOT participantIdentifier
// 2. Request the correct scope(s) for your needs.
const scopes = "Participant:read SurveyAnswers:read"
const participantAccessToken = await getParticipantAccessToken(serviceAccessToken, participant.id, scopes);
console.log(`\nObtained participant access token for ${participant.id}: ${participantAccessToken}`);
}
}
}
quickstart();