fhirsmith 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/FHIRsmith.png +0 -0
  3. package/README.md +277 -0
  4. package/config-template.json +144 -0
  5. package/library/folder-setup.js +58 -0
  6. package/library/html-server.js +166 -0
  7. package/library/html.js +835 -0
  8. package/library/i18nsupport.js +259 -0
  9. package/library/languages.js +779 -0
  10. package/library/logger-telnet.js +205 -0
  11. package/library/logger.js +279 -0
  12. package/library/package-manager.js +876 -0
  13. package/library/utilities.js +196 -0
  14. package/library/version-utilities.js +1056 -0
  15. package/npmprojector/config-example.json +13 -0
  16. package/npmprojector/indexer.js +394 -0
  17. package/npmprojector/npmprojector.js +395 -0
  18. package/npmprojector/readme.md +174 -0
  19. package/npmprojector/watcher.js +335 -0
  20. package/package.json +119 -0
  21. package/packages/package-crawler.js +846 -0
  22. package/packages/packages-template.html +126 -0
  23. package/packages/packages.js +2838 -0
  24. package/passwords.ini +2 -0
  25. package/publisher/publisher-template.html +208 -0
  26. package/publisher/publisher.js +2167 -0
  27. package/publisher/task-draft.js +458 -0
  28. package/registry/api.js +735 -0
  29. package/registry/crawler.js +637 -0
  30. package/registry/model.js +513 -0
  31. package/registry/readme.md +243 -0
  32. package/registry/registry-data.json +121015 -0
  33. package/registry/registry-template.html +126 -0
  34. package/registry/registry.js +1395 -0
  35. package/registry/test-runner.js +237 -0
  36. package/root-template.html +124 -0
  37. package/server.js +524 -0
  38. package/shl/private-key.pem +5 -0
  39. package/shl/public-key.pem +18 -0
  40. package/shl/shl.js +1125 -0
  41. package/shl/vhl.js +69 -0
  42. package/static/FHIRsmith128.png +0 -0
  43. package/static/FHIRsmith16.png +0 -0
  44. package/static/FHIRsmith32.png +0 -0
  45. package/static/FHIRsmith64.png +0 -0
  46. package/static/assets/css/bootstrap-fhir.css +5302 -0
  47. package/static/assets/css/bootstrap-glyphicons.css +2 -0
  48. package/static/assets/css/bootstrap.css +4097 -0
  49. package/static/assets/css/jquery-ui.css +523 -0
  50. package/static/assets/css/jquery-ui.structure.css +863 -0
  51. package/static/assets/css/jquery-ui.structure.min.css +5 -0
  52. package/static/assets/css/jquery-ui.theme.css +439 -0
  53. package/static/assets/css/jquery-ui.theme.min.css +5 -0
  54. package/static/assets/css/jquery.ui.all.css +7 -0
  55. package/static/assets/css/modules.css +18 -0
  56. package/static/assets/css/project.css +367 -0
  57. package/static/assets/css/pygments-manni.css +66 -0
  58. package/static/assets/css/tags.css +74 -0
  59. package/static/assets/css/xml.css +2 -0
  60. package/static/assets/fonts/glyphiconshalflings-regular.eot +0 -0
  61. package/static/assets/fonts/glyphiconshalflings-regular.otf +0 -0
  62. package/static/assets/fonts/glyphiconshalflings-regular.svg +175 -0
  63. package/static/assets/fonts/glyphiconshalflings-regular.ttf +0 -0
  64. package/static/assets/fonts/glyphiconshalflings-regular.woff +0 -0
  65. package/static/assets/ico/apple-touch-icon-114-precomposed.png +0 -0
  66. package/static/assets/ico/apple-touch-icon-144-precomposed.png +0 -0
  67. package/static/assets/ico/apple-touch-icon-57-precomposed.png +0 -0
  68. package/static/assets/ico/apple-touch-icon-72-precomposed.png +0 -0
  69. package/static/assets/ico/favicon.ico +0 -0
  70. package/static/assets/ico/favicon.png +0 -0
  71. package/static/assets/images/fhir-logo-www.png +0 -0
  72. package/static/assets/images/fhir-logo.png +0 -0
  73. package/static/assets/images/hl7-logo.png +0 -0
  74. package/static/assets/images/logo_ansinew.jpg +0 -0
  75. package/static/assets/images/search.png +0 -0
  76. package/static/assets/images/stripe.png +0 -0
  77. package/static/assets/images/target.png +0 -0
  78. package/static/assets/images/tx-registry-root.gif +0 -0
  79. package/static/assets/images/tx-registry.png +0 -0
  80. package/static/assets/images/tx-server.png +0 -0
  81. package/static/assets/images/tx-version.png +0 -0
  82. package/static/assets/js/bootstrap.min.js +6 -0
  83. package/static/assets/js/fhir-gw.js +259 -0
  84. package/static/assets/js/fhir.js +2 -0
  85. package/static/assets/js/html5shiv.js +8 -0
  86. package/static/assets/js/jcookie.js +96 -0
  87. package/static/assets/js/jquery-ui.min.js +6 -0
  88. package/static/assets/js/jquery.js +10716 -0
  89. package/static/assets/js/jquery.min.js +2 -0
  90. package/static/assets/js/jquery.ui.core.js +314 -0
  91. package/static/assets/js/jquery.ui.draggable.js +825 -0
  92. package/static/assets/js/jquery.ui.mouse.js +162 -0
  93. package/static/assets/js/jquery.ui.resizable.js +842 -0
  94. package/static/assets/js/jquery.ui.widget.js +268 -0
  95. package/static/assets/js/json2.js +487 -0
  96. package/static/assets/js/jtip.js +97 -0
  97. package/static/assets/js/respond.min.js +6 -0
  98. package/static/assets/js/statuspage.js +70 -0
  99. package/static/assets/js/xml.js +2 -0
  100. package/static/dist/js/bootstrap.js +1964 -0
  101. package/static/favicon.png +0 -0
  102. package/static/fhir.css +626 -0
  103. package/static/icon-fhir-16.png +0 -0
  104. package/static/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  105. package/static/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  106. package/static/images/ui-bg_flat_10_000000_40x100.png +0 -0
  107. package/static/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  108. package/static/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  109. package/static/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  110. package/static/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  111. package/static/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  112. package/static/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  113. package/static/images/ui-icons_222222_256x240.png +0 -0
  114. package/static/images/ui-icons_228ef1_256x240.png +0 -0
  115. package/static/images/ui-icons_ef8c08_256x240.png +0 -0
  116. package/static/images/ui-icons_ffd27a_256x240.png +0 -0
  117. package/static/images/ui-icons_ffffff_256x240.png +0 -0
  118. package/static/js/jquery.effects.blind.js +49 -0
  119. package/static/js/jquery.effects.bounce.js +78 -0
  120. package/static/js/jquery.effects.clip.js +54 -0
  121. package/static/js/jquery.effects.core.js +763 -0
  122. package/static/js/jquery.effects.drop.js +50 -0
  123. package/static/js/jquery.effects.explode.js +79 -0
  124. package/static/js/jquery.effects.fade.js +32 -0
  125. package/static/js/jquery.effects.fold.js +56 -0
  126. package/static/js/jquery.effects.highlight.js +50 -0
  127. package/static/js/jquery.effects.pulsate.js +51 -0
  128. package/static/js/jquery.effects.scale.js +178 -0
  129. package/static/js/jquery.effects.shake.js +57 -0
  130. package/static/js/jquery.effects.slide.js +50 -0
  131. package/static/js/jquery.effects.transfer.js +45 -0
  132. package/static/js/jquery.ui.accordion.js +611 -0
  133. package/static/js/jquery.ui.autocomplete.js +612 -0
  134. package/static/js/jquery.ui.button.js +416 -0
  135. package/static/js/jquery.ui.datepicker.js +1823 -0
  136. package/static/js/jquery.ui.dialog.js +878 -0
  137. package/static/js/jquery.ui.droppable.js +296 -0
  138. package/static/js/jquery.ui.position.js +252 -0
  139. package/static/js/jquery.ui.progressbar.js +109 -0
  140. package/static/js/jquery.ui.selectable.js +266 -0
  141. package/static/js/jquery.ui.slider.js +666 -0
  142. package/static/js/jquery.ui.sortable.js +1077 -0
  143. package/static/js/jquery.ui.tabs.js +758 -0
  144. package/stats.js +80 -0
  145. package/test-cache/vsac/vsac-valuesets.db +0 -0
  146. package/token/nginx_passport_setup.md +383 -0
  147. package/token/security_guide.md +294 -0
  148. package/token/token-template.html +330 -0
  149. package/token/token.js +1300 -0
  150. package/translations/Messages.properties +1510 -0
  151. package/translations/Messages_ar.properties +1399 -0
  152. package/translations/Messages_de.properties +836 -0
  153. package/translations/Messages_es.properties +737 -0
  154. package/translations/Messages_fr.properties +1 -0
  155. package/translations/Messages_ja.properties +893 -0
  156. package/translations/Messages_nl.properties +1357 -0
  157. package/translations/Messages_pt.properties +1302 -0
  158. package/translations/Messages_ru.properties +1 -0
  159. package/translations/Messages_uz.properties +1 -0
  160. package/translations/Messages_zh.properties +1 -0
  161. package/translations/rendering-phrases.properties +1128 -0
  162. package/translations/rendering-phrases_ar.properties +1091 -0
  163. package/translations/rendering-phrases_de.properties +6 -0
  164. package/translations/rendering-phrases_es.properties +6 -0
  165. package/translations/rendering-phrases_fr.properties +624 -0
  166. package/translations/rendering-phrases_ja.properties +21 -0
  167. package/translations/rendering-phrases_nl.properties +970 -0
  168. package/translations/rendering-phrases_pt.properties +1020 -0
  169. package/translations/rendering-phrases_ru.properties +1094 -0
  170. package/translations/rendering-phrases_uz.properties +1 -0
  171. package/translations/rendering-phrases_zh.properties +1 -0
  172. package/tx/README.md +418 -0
  173. package/tx/cm/cm-api.js +110 -0
  174. package/tx/cm/cm-database.js +735 -0
  175. package/tx/cm/cm-package.js +325 -0
  176. package/tx/cs/cs-api.js +789 -0
  177. package/tx/cs/cs-areacode.js +615 -0
  178. package/tx/cs/cs-country.js +1110 -0
  179. package/tx/cs/cs-cpt.js +785 -0
  180. package/tx/cs/cs-cs.js +1579 -0
  181. package/tx/cs/cs-currency.js +539 -0
  182. package/tx/cs/cs-db.js +1321 -0
  183. package/tx/cs/cs-hgvs.js +329 -0
  184. package/tx/cs/cs-lang.js +465 -0
  185. package/tx/cs/cs-loinc.js +1485 -0
  186. package/tx/cs/cs-mimetypes.js +238 -0
  187. package/tx/cs/cs-ndc.js +704 -0
  188. package/tx/cs/cs-omop.js +1025 -0
  189. package/tx/cs/cs-provider-api.js +43 -0
  190. package/tx/cs/cs-provider-list.js +37 -0
  191. package/tx/cs/cs-rxnorm.js +808 -0
  192. package/tx/cs/cs-snomed.js +1102 -0
  193. package/tx/cs/cs-ucum.js +514 -0
  194. package/tx/cs/cs-unii.js +271 -0
  195. package/tx/cs/cs-uri.js +218 -0
  196. package/tx/cs/cs-usstates.js +305 -0
  197. package/tx/dev.fhir.org.yml +14 -0
  198. package/tx/fixtures/test-cases-setup.json +18 -0
  199. package/tx/fixtures/test-cases.yml +16 -0
  200. package/tx/html/codesystem-operations.liquid +25 -0
  201. package/tx/html/home-metrics.liquid +247 -0
  202. package/tx/html/operations-form.liquid +148 -0
  203. package/tx/html/search-form.liquid +62 -0
  204. package/tx/html/tx-template.html +133 -0
  205. package/tx/html/valueset-operations.liquid +54 -0
  206. package/tx/importers/atc-to-fhir.js +316 -0
  207. package/tx/importers/import-loinc.module.js +1536 -0
  208. package/tx/importers/import-ndc.module.js +1088 -0
  209. package/tx/importers/import-rxnorm.module.js +898 -0
  210. package/tx/importers/import-sct.module.js +2457 -0
  211. package/tx/importers/import-unii.module.js +601 -0
  212. package/tx/importers/readme.md +453 -0
  213. package/tx/importers/subset-loinc.module.js +1081 -0
  214. package/tx/importers/subset-rxnorm.module.js +938 -0
  215. package/tx/importers/tx-import-base.js +351 -0
  216. package/tx/importers/tx-import-settings.js +310 -0
  217. package/tx/importers/tx-import.js +357 -0
  218. package/tx/library/canonical-resource.js +88 -0
  219. package/tx/library/capabilitystatement.js +292 -0
  220. package/tx/library/codesystem.js +774 -0
  221. package/tx/library/conceptmap.js +568 -0
  222. package/tx/library/designations.js +932 -0
  223. package/tx/library/errors.js +77 -0
  224. package/tx/library/extensions.js +117 -0
  225. package/tx/library/namingsystem.js +322 -0
  226. package/tx/library/operation-outcome.js +127 -0
  227. package/tx/library/parameters.js +105 -0
  228. package/tx/library/renderer.js +1559 -0
  229. package/tx/library/terminologycapabilities.js +418 -0
  230. package/tx/library/ucum-parsers.js +1029 -0
  231. package/tx/library/ucum-service.js +370 -0
  232. package/tx/library/ucum-types.js +1099 -0
  233. package/tx/library/valueset.js +543 -0
  234. package/tx/library.js +676 -0
  235. package/tx/ocl/cm-ocl.js +106 -0
  236. package/tx/ocl/cs-ocl.js +39 -0
  237. package/tx/ocl/vs-ocl.js +105 -0
  238. package/tx/operation-context.js +568 -0
  239. package/tx/params.js +613 -0
  240. package/tx/provider.js +403 -0
  241. package/tx/sct/ecl.js +1560 -0
  242. package/tx/sct/expressions.js +2077 -0
  243. package/tx/sct/structures.js +1396 -0
  244. package/tx/tx-html.js +1063 -0
  245. package/tx/tx.fhir.org.yml +39 -0
  246. package/tx/tx.js +927 -0
  247. package/tx/vs/vs-api.js +112 -0
  248. package/tx/vs/vs-database.js +786 -0
  249. package/tx/vs/vs-package.js +358 -0
  250. package/tx/vs/vs-vsac.js +366 -0
  251. package/tx/workers/batch-validate.js +129 -0
  252. package/tx/workers/batch.js +361 -0
  253. package/tx/workers/closure.js +32 -0
  254. package/tx/workers/expand.js +1845 -0
  255. package/tx/workers/lookup.js +407 -0
  256. package/tx/workers/metadata.js +467 -0
  257. package/tx/workers/operations.js +34 -0
  258. package/tx/workers/read.js +164 -0
  259. package/tx/workers/search.js +384 -0
  260. package/tx/workers/subsumes.js +334 -0
  261. package/tx/workers/translate.js +492 -0
  262. package/tx/workers/validate.js +2504 -0
  263. package/tx/workers/worker.js +904 -0
  264. package/tx/xml/capabilitystatement-xml.js +63 -0
  265. package/tx/xml/codesystem-xml.js +62 -0
  266. package/tx/xml/conceptmap-xml.js +65 -0
  267. package/tx/xml/namingsystem-xml.js +65 -0
  268. package/tx/xml/operationoutcome-xml.js +127 -0
  269. package/tx/xml/parameters-xml.js +312 -0
  270. package/tx/xml/terminologycapabilities-xml.js +64 -0
  271. package/tx/xml/valueset-xml.js +64 -0
  272. package/tx/xml/xml-base.js +603 -0
  273. package/vcl/vcl-parser.js +1098 -0
  274. package/vcl/vcl.js +253 -0
  275. package/windows-install.js +19 -0
  276. package/xig/xig-template.html +124 -0
  277. package/xig/xig.js +3049 -0
package/stats.js ADDED
@@ -0,0 +1,80 @@
1
+ const { monitorEventLoopDelay } = require('perf_hooks');
2
+ const {cache} = require("express/lib/application");
3
+
4
+ class ServerStats {
5
+ started = false;
6
+ requestCount = 0;
7
+ requestTime = 0;
8
+ // Collect metrics every 10 minutes
9
+ intervalMs = 10 * 60 * 1000;
10
+ history = [];
11
+ requestCountSnapshot = 0;
12
+ startMem = 0;
13
+ startTime = Date.now();
14
+ timer;
15
+ cachingModules = [];
16
+
17
+ constructor() {
18
+ this.timer = setInterval(() => {
19
+ this.recordMetrics();
20
+ }, this.intervalMs);
21
+ }
22
+
23
+ recordMetrics() {
24
+ if (this.started) {
25
+ const now = Date.now();
26
+
27
+ const currentMem = process.memoryUsage().heapUsed;
28
+ const requestsDelta = this.requestCount - this.requestCountSnapshot;
29
+ const requestsTat = requestsDelta > 0 ? this.requestTime / requestsDelta : 0;
30
+ const minutesSinceStart = this.history.length > 1
31
+ ? this.intervalMs / 60000
32
+ : (now - this.startTime) / 60000;
33
+ const requestsPerMin = minutesSinceStart > 0 ? requestsDelta / minutesSinceStart : 0;
34
+ const elapsedMs = (now - this.lastTime);
35
+ const usage = process.cpuUsage(this.lastUsage);
36
+ const cpuMs = (usage.user + usage.system) / 1000; // microseconds → milliseconds
37
+ const percent = elapsedMs > 0 ? 100 * cpuMs / elapsedMs : 0;
38
+ const loopDelay = this.eventLoopMonitor.mean / 1e6;
39
+ let cacheCount = 0;
40
+ for (let m of this.cachingModules) {
41
+ cacheCount = cacheCount + m.cacheCount();
42
+ }
43
+
44
+ this.history.push({time: now, mem: currentMem - this.startMem, rpm: requestsPerMin, tat: requestsTat, cpu: percent, block: loopDelay, cache : cacheCount});
45
+
46
+ this.eventLoopMonitor.reset();
47
+ this.requestCountSnapshot = this.requestCount;
48
+ this.requestTime = 0;
49
+ this.lastUsage = process.cpuUsage();
50
+ this.lastTime = now;
51
+
52
+ // Prune old data (keep 24 hours)
53
+ const cutoff = now - (24 * 60 * 60 * 1000); // 24 hours ago
54
+ this.history = this.history.filter(m => m.time > cutoff);
55
+ }
56
+ }
57
+
58
+ markStarted() {
59
+ this.started = true;
60
+ this.startMem = process.memoryUsage().heapUsed;
61
+ this.startTime = Date.now();
62
+ this.lastUsage = process.cpuUsage();
63
+ this.lastTime = this.startTime;
64
+ this.eventLoopMonitor = monitorEventLoopDelay({ resolution: 20 });
65
+ this.eventLoopMonitor.enable();
66
+ this.recordMetrics();
67
+ }
68
+
69
+ countRequest(name, tat) {
70
+ // we ignore name for now, but we might split the tat tracking up by name
71
+ // at some stage
72
+ this.requestCount++;
73
+ this.requestTime = this.requestTime + tat;
74
+ }
75
+
76
+ finishStats() {
77
+ clearInterval(this.timer);
78
+ }
79
+ }
80
+ module.exports = ServerStats;
@@ -0,0 +1,383 @@
1
+ # Nginx + Passport.js Configuration Guide
2
+
3
+ ## Architecture Overview
4
+
5
+ ```
6
+ Client Browser
7
+ ↓ HTTPS (443) / HTTP (80)
8
+ Nginx Reverse Proxy
9
+ ↓ HTTP (3000) - Internal Network
10
+ Node.js App (Passport.js)
11
+ ```
12
+
13
+ This setup works perfectly with Passport.js, but requires proper configuration to handle the proxy correctly.
14
+
15
+ ## Required Configuration Changes
16
+
17
+ ### 1. **Express Trust Proxy Configuration**
18
+
19
+ Add this to your main `server.js` before initializing routes:
20
+
21
+ ```javascript
22
+ // server.js - Add after creating the Express app
23
+ const app = express();
24
+
25
+ // Trust the nginx proxy - CRITICAL for proper IP handling
26
+ app.set('trust proxy', 1);
27
+
28
+ // Alternative: Trust specific proxy IP
29
+ // app.set('trust proxy', '127.0.0.1');
30
+
31
+ // Rest of your middleware...
32
+ ```
33
+
34
+ ### 2. **Updated Token Module for Proxy Support**
35
+
36
+ ```javascript
37
+ // In token.js, update session configuration
38
+ initializeSession() {
39
+ const sessionConfig = {
40
+ store: new SQLiteStore({
41
+ db: this.config.database || 'token.db',
42
+ table: 'sessions'
43
+ }),
44
+ secret: this.config.sessionSecret || crypto.randomBytes(64).toString('hex'),
45
+ name: 'fhir.token.sid',
46
+ resave: false,
47
+ saveUninitialized: false,
48
+ rolling: true,
49
+ cookie: {
50
+ // This is key - secure cookies when behind HTTPS proxy
51
+ secure: this.config.server?.httpsProxy || process.env.NODE_ENV === 'production',
52
+ httpOnly: true,
53
+ maxAge: 24 * 60 * 60 * 1000,
54
+ sameSite: 'lax'
55
+ },
56
+ proxy: true // Important for proxied environments
57
+ };
58
+
59
+ this.router.use(session(sessionConfig));
60
+ }
61
+ ```
62
+
63
+ ### 3. **Environment-Specific OAuth Configuration**
64
+
65
+ Update your `config.json` with environment-specific URLs:
66
+
67
+ ```json
68
+ {
69
+ "server": {
70
+ "port": 3000,
71
+ "httpsProxy": true,
72
+ "cors": {
73
+ "origin": true,
74
+ "credentials": true
75
+ }
76
+ },
77
+ "modules": {
78
+ "token": {
79
+ "enabled": true,
80
+ "database": "/absolute/path/to/token.db",
81
+ "sessionSecret": "your-session-secret",
82
+ "oauth": {
83
+ "google": {
84
+ "clientId": "your-google-client-id",
85
+ "clientSecret": "your-google-client-secret",
86
+ "redirectUri": "https://local.fhir.org/token/auth/google/callback",
87
+ "scope": ["openid", "profile", "email"]
88
+ },
89
+ "facebook": {
90
+ "clientId": "your-facebook-app-id",
91
+ "clientSecret": "your-facebook-app-secret",
92
+ "redirectUri": "https://local.fhir.org/token/auth/facebook/callback",
93
+ "scope": ["email"]
94
+ },
95
+ "github": {
96
+ "clientId": "your-github-client-id",
97
+ "clientSecret": "your-github-client-secret",
98
+ "redirectUri": "https://local.fhir.org/token/auth/github/callback",
99
+ "scope": ["user:email"]
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### 4. **Production Configuration**
108
+
109
+ For production, update OAuth redirect URIs to use `tokens.fhir.org`:
110
+
111
+ ```json
112
+ {
113
+ "oauth": {
114
+ "google": {
115
+ "redirectUri": "https://tokens.fhir.org/token/auth/google/callback"
116
+ },
117
+ "facebook": {
118
+ "redirectUri": "https://tokens.fhir.org/token/auth/facebook/callback"
119
+ },
120
+ "github": {
121
+ "redirectUri": "https://tokens.fhir.org/token/auth/github/callback"
122
+ }
123
+ }
124
+ }
125
+ ```
126
+
127
+ ## Nginx Configuration
128
+
129
+ ### Development (local.fhir.org)
130
+
131
+ ```nginx
132
+ server {
133
+ listen 80;
134
+ server_name local.fhir.org;
135
+ return 301 https://$server_name$request_uri;
136
+ }
137
+
138
+ server {
139
+ listen 443 ssl http2;
140
+ server_name local.fhir.org;
141
+
142
+ # SSL configuration for local development
143
+ ssl_certificate /path/to/local.fhir.org.crt;
144
+ ssl_certificate_key /path/to/local.fhir.org.key;
145
+
146
+ # Security headers
147
+ add_header X-Frame-Options SAMEORIGIN;
148
+ add_header X-Content-Type-Options nosniff;
149
+ add_header X-XSS-Protection "1; mode=block";
150
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
151
+
152
+ location / {
153
+ proxy_pass http://127.0.0.1:3000;
154
+ proxy_http_version 1.1;
155
+ proxy_set_header Upgrade $http_upgrade;
156
+ proxy_set_header Connection 'upgrade';
157
+ proxy_set_header Host $host;
158
+ proxy_set_header X-Real-IP $remote_addr;
159
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
160
+ proxy_set_header X-Forwarded-Proto $scheme;
161
+ proxy_set_header X-Forwarded-Host $host;
162
+ proxy_set_header X-Forwarded-Port $server_port;
163
+ proxy_cache_bypass $http_upgrade;
164
+
165
+ # Important for OAuth callbacks
166
+ proxy_redirect http://127.0.0.1:3000 https://local.fhir.org;
167
+ }
168
+ }
169
+ ```
170
+
171
+ ### Production (tokens.fhir.org)
172
+
173
+ ```nginx
174
+ server {
175
+ listen 80;
176
+ server_name tokens.fhir.org;
177
+ return 301 https://$server_name$request_uri;
178
+ }
179
+
180
+ server {
181
+ listen 443 ssl http2;
182
+ server_name tokens.fhir.org;
183
+
184
+ # SSL configuration
185
+ ssl_certificate /path/to/tokens.fhir.org.crt;
186
+ ssl_certificate_key /path/to/tokens.fhir.org.key;
187
+
188
+ # Enhanced security headers for production
189
+ add_header X-Frame-Options DENY;
190
+ add_header X-Content-Type-Options nosniff;
191
+ add_header X-XSS-Protection "1; mode=block";
192
+ add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
193
+ add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'";
194
+ add_header Referrer-Policy "strict-origin-when-cross-origin";
195
+
196
+ # Rate limiting
197
+ limit_req_zone $binary_remote_addr zone=auth:10m rate=5r/m;
198
+ limit_req zone=auth burst=10 nodelay;
199
+
200
+ location / {
201
+ proxy_pass http://127.0.0.1:3000;
202
+ proxy_http_version 1.1;
203
+ proxy_set_header Upgrade $http_upgrade;
204
+ proxy_set_header Connection 'upgrade';
205
+ proxy_set_header Host $host;
206
+ proxy_set_header X-Real-IP $remote_addr;
207
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
208
+ proxy_set_header X-Forwarded-Proto $scheme;
209
+ proxy_set_header X-Forwarded-Host $host;
210
+ proxy_set_header X-Forwarded-Port $server_port;
211
+ proxy_cache_bypass $http_upgrade;
212
+
213
+ # Timeouts
214
+ proxy_connect_timeout 60s;
215
+ proxy_send_timeout 60s;
216
+ proxy_read_timeout 60s;
217
+
218
+ proxy_redirect http://127.0.0.1:3000 https://tokens.fhir.org;
219
+ }
220
+
221
+ # Optional: Serve static files directly from nginx
222
+ location /assets/ {
223
+ alias /path/to/app/static/assets/;
224
+ expires 1y;
225
+ add_header Cache-Control "public, immutable";
226
+ }
227
+ }
228
+ ```
229
+
230
+ ## OAuth Provider Registration
231
+
232
+ ### Development URLs
233
+ When registering your app with OAuth providers for development:
234
+
235
+ **Google Cloud Console:**
236
+ - Authorized JavaScript origins: `https://local.fhir.org`
237
+ - Authorized redirect URIs: `https://local.fhir.org/token/auth/google/callback`
238
+
239
+ **Facebook for Developers:**
240
+ - Valid OAuth Redirect URIs: `https://local.fhir.org/token/auth/facebook/callback`
241
+ - App Domains: `local.fhir.org`
242
+
243
+ **GitHub OAuth Apps:**
244
+ - Authorization callback URL: `https://local.fhir.org/token/auth/github/callback`
245
+
246
+ ### Production URLs
247
+ For production, register separate apps or add additional URLs:
248
+
249
+ - Google: `https://tokens.fhir.org/token/auth/google/callback`
250
+ - Facebook: `https://tokens.fhir.org/token/auth/facebook/callback`
251
+ - GitHub: `https://tokens.fhir.org/token/auth/github/callback`
252
+
253
+ ## Environment Configuration
254
+
255
+ ### Development Environment Variables
256
+
257
+ ```bash
258
+ # .env.development
259
+ NODE_ENV=development
260
+ PORT=3000
261
+ SESSION_SECRET=your-dev-session-secret
262
+ BEHIND_PROXY=true
263
+
264
+ # OAuth Development
265
+ GOOGLE_CLIENT_ID=your-dev-google-client-id
266
+ GOOGLE_CLIENT_SECRET=your-dev-google-client-secret
267
+ FACEBOOK_CLIENT_ID=your-dev-facebook-client-id
268
+ FACEBOOK_CLIENT_SECRET=your-dev-facebook-client-secret
269
+ GITHUB_CLIENT_ID=your-dev-github-client-id
270
+ GITHUB_CLIENT_SECRET=your-dev-github-client-secret
271
+ ```
272
+
273
+ ### Production Environment Variables
274
+
275
+ ```bash
276
+ # .env.production
277
+ NODE_ENV=production
278
+ PORT=3000
279
+ SESSION_SECRET=your-production-session-secret-64-chars-minimum
280
+ BEHIND_PROXY=true
281
+
282
+ # OAuth Production
283
+ GOOGLE_CLIENT_ID=your-prod-google-client-id
284
+ GOOGLE_CLIENT_SECRET=your-prod-google-client-secret
285
+ FACEBOOK_CLIENT_ID=your-prod-facebook-client-id
286
+ FACEBOOK_CLIENT_SECRET=your-prod-facebook-client-secret
287
+ GITHUB_CLIENT_ID=your-prod-github-client-id
288
+ GITHUB_CLIENT_SECRET=your-prod-github-client-secret
289
+ ```
290
+
291
+ ## Configuration Loading
292
+
293
+ Update your server.js to handle environment-specific configs:
294
+
295
+ ```javascript
296
+ // server.js - Enhanced configuration loading
297
+ let config;
298
+ try {
299
+ const configFile = process.env.NODE_ENV === 'production' ? 'config.production.json' : 'config.json';
300
+ const configPath = path.join(__dirname, configFile);
301
+ const configData = fs.readFileSync(configPath, 'utf8');
302
+ config = JSON.parse(configData);
303
+
304
+ // Override with environment variables if present
305
+ if (process.env.SESSION_SECRET) {
306
+ config.modules.token.sessionSecret = process.env.SESSION_SECRET;
307
+ }
308
+
309
+ // OAuth environment overrides
310
+ const oauthOverrides = {
311
+ google: {
312
+ clientId: process.env.GOOGLE_CLIENT_ID,
313
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET
314
+ },
315
+ facebook: {
316
+ clientId: process.env.FACEBOOK_CLIENT_ID,
317
+ clientSecret: process.env.FACEBOOK_CLIENT_SECRET
318
+ },
319
+ github: {
320
+ clientId: process.env.GITHUB_CLIENT_ID,
321
+ clientSecret: process.env.GITHUB_CLIENT_SECRET
322
+ }
323
+ };
324
+
325
+ Object.keys(oauthOverrides).forEach(provider => {
326
+ if (config.modules.token.oauth[provider] && oauthOverrides[provider].clientId) {
327
+ config.modules.token.oauth[provider] = {
328
+ ...config.modules.token.oauth[provider],
329
+ ...oauthOverrides[provider]
330
+ };
331
+ }
332
+ });
333
+
334
+ serverLog.info(`Loaded ${configFile}. Active modules = ${Object.keys(config.modules).filter(mod => config.modules[mod].enabled).join(', ')}`);
335
+ } catch (error) {
336
+ serverLog.error('Failed to load configuration:', error.message);
337
+ process.exit(1);
338
+ }
339
+ ```
340
+
341
+ ## Testing the Setup
342
+
343
+ ### 1. **Local Development Test**
344
+ ```bash
345
+ # Start your Node.js server
346
+ npm run dev
347
+
348
+ # Test the OAuth flow
349
+ curl -I https://local.fhir.org/token/auth/google
350
+
351
+ # Should return 302 redirect to Google OAuth
352
+ ```
353
+
354
+ ### 2. **Production Deployment Test**
355
+ ```bash
356
+ # Test OAuth endpoints
357
+ curl -I https://tokens.fhir.org/token/auth/google
358
+ curl -I https://tokens.fhir.org/token/auth/facebook
359
+ curl -I https://tokens.fhir.org/token/auth/github
360
+ ```
361
+
362
+ ## Troubleshooting Common Issues
363
+
364
+ ### 1. **"Invalid Redirect URI" Error**
365
+ - Ensure OAuth app registration URLs exactly match your callback URLs
366
+ - Check for trailing slashes in URLs
367
+ - Verify HTTPS vs HTTP protocol
368
+
369
+ ### 2. **Session Issues Behind Proxy**
370
+ - Ensure `app.set('trust proxy', 1)` is set
371
+ - Verify nginx proxy headers are correctly configured
372
+ - Check that `secure: true` is set for cookies in production
373
+
374
+ ### 3. **CSRF Token Errors**
375
+ - Verify nginx is passing all headers correctly
376
+ - Ensure `X-Forwarded-Proto` header is set to `https`
377
+ - Check that `sameSite` cookie setting is appropriate
378
+
379
+ ### 4. **IP Address Logging Issues**
380
+ - If you see 127.0.0.1 instead of real IPs, check `trust proxy` setting
381
+ - Verify `X-Real-IP` and `X-Forwarded-For` headers in nginx config
382
+
383
+ This setup provides a robust, production-ready OAuth implementation behind nginx proxy that works seamlessly with Passport.js!