@portaidentity/server 1.7.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 (742) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +33 -0
  4. package/dist/applications/cache.d.ts +64 -0
  5. package/dist/applications/cache.d.ts.map +1 -0
  6. package/dist/applications/cache.js +161 -0
  7. package/dist/applications/cache.js.map +1 -0
  8. package/dist/applications/errors.d.ts +25 -0
  9. package/dist/applications/errors.d.ts.map +1 -0
  10. package/dist/applications/errors.js +31 -0
  11. package/dist/applications/errors.js.map +1 -0
  12. package/dist/applications/index.d.ts +17 -0
  13. package/dist/applications/index.d.ts.map +1 -0
  14. package/dist/applications/index.js +19 -0
  15. package/dist/applications/index.js.map +1 -0
  16. package/dist/applications/repository.d.ts +184 -0
  17. package/dist/applications/repository.d.ts.map +1 -0
  18. package/dist/applications/repository.js +367 -0
  19. package/dist/applications/repository.js.map +1 -0
  20. package/dist/applications/service.d.ts +160 -0
  21. package/dist/applications/service.d.ts.map +1 -0
  22. package/dist/applications/service.js +388 -0
  23. package/dist/applications/service.js.map +1 -0
  24. package/dist/applications/slugs.d.ts +61 -0
  25. package/dist/applications/slugs.d.ts.map +1 -0
  26. package/dist/applications/slugs.js +115 -0
  27. package/dist/applications/slugs.js.map +1 -0
  28. package/dist/applications/types.d.ts +129 -0
  29. package/dist/applications/types.d.ts.map +1 -0
  30. package/dist/applications/types.js +62 -0
  31. package/dist/applications/types.js.map +1 -0
  32. package/dist/auth/csrf.d.ts +71 -0
  33. package/dist/auth/csrf.d.ts.map +1 -0
  34. package/dist/auth/csrf.js +112 -0
  35. package/dist/auth/csrf.js.map +1 -0
  36. package/dist/auth/email-renderer.d.ts +37 -0
  37. package/dist/auth/email-renderer.d.ts.map +1 -0
  38. package/dist/auth/email-renderer.js +116 -0
  39. package/dist/auth/email-renderer.js.map +1 -0
  40. package/dist/auth/email-service.d.ts +154 -0
  41. package/dist/auth/email-service.d.ts.map +1 -0
  42. package/dist/auth/email-service.js +415 -0
  43. package/dist/auth/email-service.js.map +1 -0
  44. package/dist/auth/email-transport.d.ts +65 -0
  45. package/dist/auth/email-transport.d.ts.map +1 -0
  46. package/dist/auth/email-transport.js +82 -0
  47. package/dist/auth/email-transport.js.map +1 -0
  48. package/dist/auth/i18n.d.ts +81 -0
  49. package/dist/auth/i18n.d.ts.map +1 -0
  50. package/dist/auth/i18n.js +395 -0
  51. package/dist/auth/i18n.js.map +1 -0
  52. package/dist/auth/index.d.ts +28 -0
  53. package/dist/auth/index.d.ts.map +1 -0
  54. package/dist/auth/index.js +31 -0
  55. package/dist/auth/index.js.map +1 -0
  56. package/dist/auth/interaction-authority.d.ts +39 -0
  57. package/dist/auth/interaction-authority.d.ts.map +1 -0
  58. package/dist/auth/interaction-authority.js +30 -0
  59. package/dist/auth/interaction-authority.js.map +1 -0
  60. package/dist/auth/magic-link-session.d.ts +81 -0
  61. package/dist/auth/magic-link-session.d.ts.map +1 -0
  62. package/dist/auth/magic-link-session.js +183 -0
  63. package/dist/auth/magic-link-session.js.map +1 -0
  64. package/dist/auth/rate-limiter.d.ts +143 -0
  65. package/dist/auth/rate-limiter.d.ts.map +1 -0
  66. package/dist/auth/rate-limiter.js +220 -0
  67. package/dist/auth/rate-limiter.js.map +1 -0
  68. package/dist/auth/recovery-crypto.d.ts +34 -0
  69. package/dist/auth/recovery-crypto.d.ts.map +1 -0
  70. package/dist/auth/recovery-crypto.js +103 -0
  71. package/dist/auth/recovery-crypto.js.map +1 -0
  72. package/dist/auth/recovery-job-processor.d.ts +24 -0
  73. package/dist/auth/recovery-job-processor.d.ts.map +1 -0
  74. package/dist/auth/recovery-job-processor.js +123 -0
  75. package/dist/auth/recovery-job-processor.js.map +1 -0
  76. package/dist/auth/recovery-job-repository.d.ts +219 -0
  77. package/dist/auth/recovery-job-repository.d.ts.map +1 -0
  78. package/dist/auth/recovery-job-repository.js +340 -0
  79. package/dist/auth/recovery-job-repository.js.map +1 -0
  80. package/dist/auth/recovery-service.d.ts +27 -0
  81. package/dist/auth/recovery-service.d.ts.map +1 -0
  82. package/dist/auth/recovery-service.js +53 -0
  83. package/dist/auth/recovery-service.js.map +1 -0
  84. package/dist/auth/recovery-worker.d.ts +158 -0
  85. package/dist/auth/recovery-worker.d.ts.map +1 -0
  86. package/dist/auth/recovery-worker.js +306 -0
  87. package/dist/auth/recovery-worker.js.map +1 -0
  88. package/dist/auth/template-engine.d.ts +134 -0
  89. package/dist/auth/template-engine.d.ts.map +1 -0
  90. package/dist/auth/template-engine.js +225 -0
  91. package/dist/auth/template-engine.js.map +1 -0
  92. package/dist/auth/token-repository.d.ts +238 -0
  93. package/dist/auth/token-repository.d.ts.map +1 -0
  94. package/dist/auth/token-repository.js +475 -0
  95. package/dist/auth/token-repository.js.map +1 -0
  96. package/dist/auth/tokens.d.ts +45 -0
  97. package/dist/auth/tokens.d.ts.map +1 -0
  98. package/dist/auth/tokens.js +51 -0
  99. package/dist/auth/tokens.js.map +1 -0
  100. package/dist/cli/bootstrap.d.ts +55 -0
  101. package/dist/cli/bootstrap.d.ts.map +1 -0
  102. package/dist/cli/bootstrap.js +90 -0
  103. package/dist/cli/bootstrap.js.map +1 -0
  104. package/dist/cli/commands/health.d.ts +20 -0
  105. package/dist/cli/commands/health.d.ts.map +1 -0
  106. package/dist/cli/commands/health.js +80 -0
  107. package/dist/cli/commands/health.js.map +1 -0
  108. package/dist/cli/commands/init.d.ts +48 -0
  109. package/dist/cli/commands/init.d.ts.map +1 -0
  110. package/dist/cli/commands/init.js +349 -0
  111. package/dist/cli/commands/init.js.map +1 -0
  112. package/dist/cli/commands/migrate.d.ts +19 -0
  113. package/dist/cli/commands/migrate.d.ts.map +1 -0
  114. package/dist/cli/commands/migrate.js +88 -0
  115. package/dist/cli/commands/migrate.js.map +1 -0
  116. package/dist/cli/commands/seed.d.ts +19 -0
  117. package/dist/cli/commands/seed.d.ts.map +1 -0
  118. package/dist/cli/commands/seed.js +71 -0
  119. package/dist/cli/commands/seed.js.map +1 -0
  120. package/dist/cli/commands/user-2fa.d.ts +29 -0
  121. package/dist/cli/commands/user-2fa.d.ts.map +1 -0
  122. package/dist/cli/commands/user-2fa.js +113 -0
  123. package/dist/cli/commands/user-2fa.js.map +1 -0
  124. package/dist/cli/error-handler.d.ts +31 -0
  125. package/dist/cli/error-handler.d.ts.map +1 -0
  126. package/dist/cli/error-handler.js +65 -0
  127. package/dist/cli/error-handler.js.map +1 -0
  128. package/dist/cli/index.d.ts +48 -0
  129. package/dist/cli/index.d.ts.map +1 -0
  130. package/dist/cli/index.js +99 -0
  131. package/dist/cli/index.js.map +1 -0
  132. package/dist/cli/output.d.ts +94 -0
  133. package/dist/cli/output.d.ts.map +1 -0
  134. package/dist/cli/output.js +124 -0
  135. package/dist/cli/output.js.map +1 -0
  136. package/dist/cli/prompt.d.ts +48 -0
  137. package/dist/cli/prompt.d.ts.map +1 -0
  138. package/dist/cli/prompt.js +96 -0
  139. package/dist/cli/prompt.js.map +1 -0
  140. package/dist/clients/cache.d.ts +63 -0
  141. package/dist/clients/cache.d.ts.map +1 -0
  142. package/dist/clients/cache.js +160 -0
  143. package/dist/clients/cache.js.map +1 -0
  144. package/dist/clients/crypto.d.ts +69 -0
  145. package/dist/clients/crypto.d.ts.map +1 -0
  146. package/dist/clients/crypto.js +83 -0
  147. package/dist/clients/crypto.js.map +1 -0
  148. package/dist/clients/errors.d.ts +27 -0
  149. package/dist/clients/errors.d.ts.map +1 -0
  150. package/dist/clients/errors.js +33 -0
  151. package/dist/clients/errors.js.map +1 -0
  152. package/dist/clients/index.d.ts +19 -0
  153. package/dist/clients/index.d.ts.map +1 -0
  154. package/dist/clients/index.js +23 -0
  155. package/dist/clients/index.js.map +1 -0
  156. package/dist/clients/repository.d.ts +161 -0
  157. package/dist/clients/repository.d.ts.map +1 -0
  158. package/dist/clients/repository.js +318 -0
  159. package/dist/clients/repository.js.map +1 -0
  160. package/dist/clients/resolve-login-methods.d.ts +74 -0
  161. package/dist/clients/resolve-login-methods.d.ts.map +1 -0
  162. package/dist/clients/resolve-login-methods.js +68 -0
  163. package/dist/clients/resolve-login-methods.js.map +1 -0
  164. package/dist/clients/secret-repository.d.ts +109 -0
  165. package/dist/clients/secret-repository.d.ts.map +1 -0
  166. package/dist/clients/secret-repository.js +166 -0
  167. package/dist/clients/secret-repository.js.map +1 -0
  168. package/dist/clients/secret-service.d.ts +87 -0
  169. package/dist/clients/secret-service.d.ts.map +1 -0
  170. package/dist/clients/secret-service.js +204 -0
  171. package/dist/clients/secret-service.js.map +1 -0
  172. package/dist/clients/service.d.ts +158 -0
  173. package/dist/clients/service.d.ts.map +1 -0
  174. package/dist/clients/service.js +523 -0
  175. package/dist/clients/service.js.map +1 -0
  176. package/dist/clients/types.d.ts +214 -0
  177. package/dist/clients/types.d.ts.map +1 -0
  178. package/dist/clients/types.js +77 -0
  179. package/dist/clients/types.js.map +1 -0
  180. package/dist/clients/validators.d.ts +87 -0
  181. package/dist/clients/validators.d.ts.map +1 -0
  182. package/dist/clients/validators.js +164 -0
  183. package/dist/clients/validators.js.map +1 -0
  184. package/dist/config/index.d.ts +23 -0
  185. package/dist/config/index.d.ts.map +1 -0
  186. package/dist/config/index.js +52 -0
  187. package/dist/config/index.js.map +1 -0
  188. package/dist/config/schema.d.ts +35 -0
  189. package/dist/config/schema.d.ts.map +1 -0
  190. package/dist/config/schema.js +167 -0
  191. package/dist/config/schema.js.map +1 -0
  192. package/dist/custom-claims/cache.d.ts +48 -0
  193. package/dist/custom-claims/cache.d.ts.map +1 -0
  194. package/dist/custom-claims/cache.js +122 -0
  195. package/dist/custom-claims/cache.js.map +1 -0
  196. package/dist/custom-claims/errors.d.ts +25 -0
  197. package/dist/custom-claims/errors.d.ts.map +1 -0
  198. package/dist/custom-claims/errors.js +31 -0
  199. package/dist/custom-claims/errors.js.map +1 -0
  200. package/dist/custom-claims/index.d.ts +14 -0
  201. package/dist/custom-claims/index.d.ts.map +1 -0
  202. package/dist/custom-claims/index.js +17 -0
  203. package/dist/custom-claims/index.js.map +1 -0
  204. package/dist/custom-claims/repository.d.ts +147 -0
  205. package/dist/custom-claims/repository.d.ts.map +1 -0
  206. package/dist/custom-claims/repository.js +338 -0
  207. package/dist/custom-claims/repository.js.map +1 -0
  208. package/dist/custom-claims/service.d.ts +129 -0
  209. package/dist/custom-claims/service.d.ts.map +1 -0
  210. package/dist/custom-claims/service.js +296 -0
  211. package/dist/custom-claims/service.js.map +1 -0
  212. package/dist/custom-claims/types.d.ts +132 -0
  213. package/dist/custom-claims/types.d.ts.map +1 -0
  214. package/dist/custom-claims/types.js +61 -0
  215. package/dist/custom-claims/types.js.map +1 -0
  216. package/dist/custom-claims/validators.d.ts +61 -0
  217. package/dist/custom-claims/validators.d.ts.map +1 -0
  218. package/dist/custom-claims/validators.js +136 -0
  219. package/dist/custom-claims/validators.js.map +1 -0
  220. package/dist/index.d.ts +14 -0
  221. package/dist/index.d.ts.map +1 -0
  222. package/dist/index.js +91 -0
  223. package/dist/index.js.map +1 -0
  224. package/dist/lib/admin-permissions.d.ts +147 -0
  225. package/dist/lib/admin-permissions.d.ts.map +1 -0
  226. package/dist/lib/admin-permissions.js +261 -0
  227. package/dist/lib/admin-permissions.js.map +1 -0
  228. package/dist/lib/audit-log.d.ts +45 -0
  229. package/dist/lib/audit-log.d.ts.map +1 -0
  230. package/dist/lib/audit-log.js +79 -0
  231. package/dist/lib/audit-log.js.map +1 -0
  232. package/dist/lib/branding-assets.d.ts +47 -0
  233. package/dist/lib/branding-assets.d.ts.map +1 -0
  234. package/dist/lib/branding-assets.js +93 -0
  235. package/dist/lib/branding-assets.js.map +1 -0
  236. package/dist/lib/bulk-operations.d.ts +54 -0
  237. package/dist/lib/bulk-operations.d.ts.map +1 -0
  238. package/dist/lib/bulk-operations.js +201 -0
  239. package/dist/lib/bulk-operations.js.map +1 -0
  240. package/dist/lib/cursor.d.ts +110 -0
  241. package/dist/lib/cursor.d.ts.map +1 -0
  242. package/dist/lib/cursor.js +115 -0
  243. package/dist/lib/cursor.js.map +1 -0
  244. package/dist/lib/data-export.d.ts +67 -0
  245. package/dist/lib/data-export.d.ts.map +1 -0
  246. package/dist/lib/data-export.js +272 -0
  247. package/dist/lib/data-export.js.map +1 -0
  248. package/dist/lib/data-import-plan.d.ts +50 -0
  249. package/dist/lib/data-import-plan.d.ts.map +1 -0
  250. package/dist/lib/data-import-plan.js +235 -0
  251. package/dist/lib/data-import-plan.js.map +1 -0
  252. package/dist/lib/data-import.d.ts +276 -0
  253. package/dist/lib/data-import.d.ts.map +1 -0
  254. package/dist/lib/data-import.js +1694 -0
  255. package/dist/lib/data-import.js.map +1 -0
  256. package/dist/lib/database.d.ts +22 -0
  257. package/dist/lib/database.d.ts.map +1 -0
  258. package/dist/lib/database.js +103 -0
  259. package/dist/lib/database.js.map +1 -0
  260. package/dist/lib/entity-history.d.ts +52 -0
  261. package/dist/lib/entity-history.d.ts.map +1 -0
  262. package/dist/lib/entity-history.js +121 -0
  263. package/dist/lib/entity-history.js.map +1 -0
  264. package/dist/lib/etag.d.ts +92 -0
  265. package/dist/lib/etag.d.ts.map +1 -0
  266. package/dist/lib/etag.js +155 -0
  267. package/dist/lib/etag.js.map +1 -0
  268. package/dist/lib/image-validator.d.ts +44 -0
  269. package/dist/lib/image-validator.d.ts.map +1 -0
  270. package/dist/lib/image-validator.js +204 -0
  271. package/dist/lib/image-validator.js.map +1 -0
  272. package/dist/lib/logger.d.ts +15 -0
  273. package/dist/lib/logger.d.ts.map +1 -0
  274. package/dist/lib/logger.js +84 -0
  275. package/dist/lib/logger.js.map +1 -0
  276. package/dist/lib/migrator.d.ts +14 -0
  277. package/dist/lib/migrator.d.ts.map +1 -0
  278. package/dist/lib/migrator.js +34 -0
  279. package/dist/lib/migrator.js.map +1 -0
  280. package/dist/lib/redis.d.ts +5 -0
  281. package/dist/lib/redis.d.ts.map +1 -0
  282. package/dist/lib/redis.js +29 -0
  283. package/dist/lib/redis.js.map +1 -0
  284. package/dist/lib/runtime-paths.d.ts +38 -0
  285. package/dist/lib/runtime-paths.d.ts.map +1 -0
  286. package/dist/lib/runtime-paths.js +50 -0
  287. package/dist/lib/runtime-paths.js.map +1 -0
  288. package/dist/lib/session-tracking.d.ts +81 -0
  289. package/dist/lib/session-tracking.d.ts.map +1 -0
  290. package/dist/lib/session-tracking.js +145 -0
  291. package/dist/lib/session-tracking.js.map +1 -0
  292. package/dist/lib/signing-key-crypto.d.ts +53 -0
  293. package/dist/lib/signing-key-crypto.d.ts.map +1 -0
  294. package/dist/lib/signing-key-crypto.js +108 -0
  295. package/dist/lib/signing-key-crypto.js.map +1 -0
  296. package/dist/lib/signing-keys.d.ts +141 -0
  297. package/dist/lib/signing-keys.d.ts.map +1 -0
  298. package/dist/lib/signing-keys.js +206 -0
  299. package/dist/lib/signing-keys.js.map +1 -0
  300. package/dist/lib/stats.d.ts +83 -0
  301. package/dist/lib/stats.d.ts.map +1 -0
  302. package/dist/lib/stats.js +187 -0
  303. package/dist/lib/stats.js.map +1 -0
  304. package/dist/lib/super-admin-protection.d.ts +69 -0
  305. package/dist/lib/super-admin-protection.d.ts.map +1 -0
  306. package/dist/lib/super-admin-protection.js +102 -0
  307. package/dist/lib/super-admin-protection.js.map +1 -0
  308. package/dist/lib/system-config.d.ts +79 -0
  309. package/dist/lib/system-config.d.ts.map +1 -0
  310. package/dist/lib/system-config.js +159 -0
  311. package/dist/lib/system-config.js.map +1 -0
  312. package/dist/middleware/admin-auth.d.ts +100 -0
  313. package/dist/middleware/admin-auth.d.ts.map +1 -0
  314. package/dist/middleware/admin-auth.js +241 -0
  315. package/dist/middleware/admin-auth.js.map +1 -0
  316. package/dist/middleware/admin-cors.d.ts +41 -0
  317. package/dist/middleware/admin-cors.d.ts.map +1 -0
  318. package/dist/middleware/admin-cors.js +83 -0
  319. package/dist/middleware/admin-cors.js.map +1 -0
  320. package/dist/middleware/admin-mutation-audit.d.ts +9 -0
  321. package/dist/middleware/admin-mutation-audit.d.ts.map +1 -0
  322. package/dist/middleware/admin-mutation-audit.js +76 -0
  323. package/dist/middleware/admin-mutation-audit.js.map +1 -0
  324. package/dist/middleware/admin-rate-limiter.d.ts +56 -0
  325. package/dist/middleware/admin-rate-limiter.d.ts.map +1 -0
  326. package/dist/middleware/admin-rate-limiter.js +97 -0
  327. package/dist/middleware/admin-rate-limiter.js.map +1 -0
  328. package/dist/middleware/client-secret-hash.d.ts +34 -0
  329. package/dist/middleware/client-secret-hash.d.ts.map +1 -0
  330. package/dist/middleware/client-secret-hash.js +74 -0
  331. package/dist/middleware/client-secret-hash.js.map +1 -0
  332. package/dist/middleware/error-handler.d.ts +3 -0
  333. package/dist/middleware/error-handler.d.ts.map +1 -0
  334. package/dist/middleware/error-handler.js +93 -0
  335. package/dist/middleware/error-handler.js.map +1 -0
  336. package/dist/middleware/health.d.ts +3 -0
  337. package/dist/middleware/health.d.ts.map +1 -0
  338. package/dist/middleware/health.js +35 -0
  339. package/dist/middleware/health.js.map +1 -0
  340. package/dist/middleware/metrics.d.ts +40 -0
  341. package/dist/middleware/metrics.d.ts.map +1 -0
  342. package/dist/middleware/metrics.js +75 -0
  343. package/dist/middleware/metrics.js.map +1 -0
  344. package/dist/middleware/oidc-client-tenant.d.ts +37 -0
  345. package/dist/middleware/oidc-client-tenant.d.ts.map +1 -0
  346. package/dist/middleware/oidc-client-tenant.js +156 -0
  347. package/dist/middleware/oidc-client-tenant.js.map +1 -0
  348. package/dist/middleware/oidc-cors.d.ts +33 -0
  349. package/dist/middleware/oidc-cors.d.ts.map +1 -0
  350. package/dist/middleware/oidc-cors.js +68 -0
  351. package/dist/middleware/oidc-cors.js.map +1 -0
  352. package/dist/middleware/oidc-preflight-cors.d.ts +54 -0
  353. package/dist/middleware/oidc-preflight-cors.d.ts.map +1 -0
  354. package/dist/middleware/oidc-preflight-cors.js +267 -0
  355. package/dist/middleware/oidc-preflight-cors.js.map +1 -0
  356. package/dist/middleware/prompt-login-reset.d.ts +103 -0
  357. package/dist/middleware/prompt-login-reset.d.ts.map +1 -0
  358. package/dist/middleware/prompt-login-reset.js +204 -0
  359. package/dist/middleware/prompt-login-reset.js.map +1 -0
  360. package/dist/middleware/ready.d.ts +23 -0
  361. package/dist/middleware/ready.d.ts.map +1 -0
  362. package/dist/middleware/ready.js +60 -0
  363. package/dist/middleware/ready.js.map +1 -0
  364. package/dist/middleware/request-logger.d.ts +27 -0
  365. package/dist/middleware/request-logger.d.ts.map +1 -0
  366. package/dist/middleware/request-logger.js +46 -0
  367. package/dist/middleware/request-logger.js.map +1 -0
  368. package/dist/middleware/require-permission.d.ts +28 -0
  369. package/dist/middleware/require-permission.d.ts.map +1 -0
  370. package/dist/middleware/require-permission.js +63 -0
  371. package/dist/middleware/require-permission.js.map +1 -0
  372. package/dist/middleware/require-user-organization.d.ts +18 -0
  373. package/dist/middleware/require-user-organization.d.ts.map +1 -0
  374. package/dist/middleware/require-user-organization.js +53 -0
  375. package/dist/middleware/require-user-organization.js.map +1 -0
  376. package/dist/middleware/root-page.d.ts +62 -0
  377. package/dist/middleware/root-page.d.ts.map +1 -0
  378. package/dist/middleware/root-page.js +134 -0
  379. package/dist/middleware/root-page.js.map +1 -0
  380. package/dist/middleware/security-headers.d.ts +98 -0
  381. package/dist/middleware/security-headers.d.ts.map +1 -0
  382. package/dist/middleware/security-headers.js +159 -0
  383. package/dist/middleware/security-headers.js.map +1 -0
  384. package/dist/middleware/tenant-resolver.d.ts +37 -0
  385. package/dist/middleware/tenant-resolver.d.ts.map +1 -0
  386. package/dist/middleware/tenant-resolver.js +71 -0
  387. package/dist/middleware/tenant-resolver.js.map +1 -0
  388. package/dist/middleware/token-rate-limiter.d.ts +89 -0
  389. package/dist/middleware/token-rate-limiter.d.ts.map +1 -0
  390. package/dist/middleware/token-rate-limiter.js +189 -0
  391. package/dist/middleware/token-rate-limiter.js.map +1 -0
  392. package/dist/oidc/account-finder.d.ts +52 -0
  393. package/dist/oidc/account-finder.d.ts.map +1 -0
  394. package/dist/oidc/account-finder.js +134 -0
  395. package/dist/oidc/account-finder.js.map +1 -0
  396. package/dist/oidc/adapter-factory.d.ts +90 -0
  397. package/dist/oidc/adapter-factory.d.ts.map +1 -0
  398. package/dist/oidc/adapter-factory.js +165 -0
  399. package/dist/oidc/adapter-factory.js.map +1 -0
  400. package/dist/oidc/configuration.d.ts +155 -0
  401. package/dist/oidc/configuration.d.ts.map +1 -0
  402. package/dist/oidc/configuration.js +531 -0
  403. package/dist/oidc/configuration.js.map +1 -0
  404. package/dist/oidc/postgres-adapter.d.ts +159 -0
  405. package/dist/oidc/postgres-adapter.d.ts.map +1 -0
  406. package/dist/oidc/postgres-adapter.js +222 -0
  407. package/dist/oidc/postgres-adapter.js.map +1 -0
  408. package/dist/oidc/protocol-security-observer.d.ts +38 -0
  409. package/dist/oidc/protocol-security-observer.d.ts.map +1 -0
  410. package/dist/oidc/protocol-security-observer.js +93 -0
  411. package/dist/oidc/protocol-security-observer.js.map +1 -0
  412. package/dist/oidc/provider.d.ts +37 -0
  413. package/dist/oidc/provider.d.ts.map +1 -0
  414. package/dist/oidc/provider.js +71 -0
  415. package/dist/oidc/provider.js.map +1 -0
  416. package/dist/oidc/redis-adapter.d.ts +140 -0
  417. package/dist/oidc/redis-adapter.d.ts.map +1 -0
  418. package/dist/oidc/redis-adapter.js +344 -0
  419. package/dist/oidc/redis-adapter.js.map +1 -0
  420. package/dist/organizations/cache.d.ts +60 -0
  421. package/dist/organizations/cache.d.ts.map +1 -0
  422. package/dist/organizations/cache.js +157 -0
  423. package/dist/organizations/cache.js.map +1 -0
  424. package/dist/organizations/errors.d.ts +25 -0
  425. package/dist/organizations/errors.d.ts.map +1 -0
  426. package/dist/organizations/errors.js +31 -0
  427. package/dist/organizations/errors.js.map +1 -0
  428. package/dist/organizations/index.d.ts +15 -0
  429. package/dist/organizations/index.d.ts.map +1 -0
  430. package/dist/organizations/index.js +15 -0
  431. package/dist/organizations/index.js.map +1 -0
  432. package/dist/organizations/repository.d.ts +183 -0
  433. package/dist/organizations/repository.d.ts.map +1 -0
  434. package/dist/organizations/repository.js +354 -0
  435. package/dist/organizations/repository.js.map +1 -0
  436. package/dist/organizations/service.d.ts +168 -0
  437. package/dist/organizations/service.d.ts.map +1 -0
  438. package/dist/organizations/service.js +511 -0
  439. package/dist/organizations/service.js.map +1 -0
  440. package/dist/organizations/slugs.d.ts +57 -0
  441. package/dist/organizations/slugs.d.ts.map +1 -0
  442. package/dist/organizations/slugs.js +130 -0
  443. package/dist/organizations/slugs.js.map +1 -0
  444. package/dist/organizations/types.d.ts +146 -0
  445. package/dist/organizations/types.d.ts.map +1 -0
  446. package/dist/organizations/types.js +49 -0
  447. package/dist/organizations/types.js.map +1 -0
  448. package/dist/rbac/cache.d.ts +110 -0
  449. package/dist/rbac/cache.d.ts.map +1 -0
  450. package/dist/rbac/cache.js +271 -0
  451. package/dist/rbac/cache.js.map +1 -0
  452. package/dist/rbac/errors.d.ts +34 -0
  453. package/dist/rbac/errors.d.ts.map +1 -0
  454. package/dist/rbac/errors.js +43 -0
  455. package/dist/rbac/errors.js.map +1 -0
  456. package/dist/rbac/index.d.ts +17 -0
  457. package/dist/rbac/index.d.ts.map +1 -0
  458. package/dist/rbac/index.js +21 -0
  459. package/dist/rbac/index.js.map +1 -0
  460. package/dist/rbac/mapping-repository.d.ts +121 -0
  461. package/dist/rbac/mapping-repository.d.ts.map +1 -0
  462. package/dist/rbac/mapping-repository.js +224 -0
  463. package/dist/rbac/mapping-repository.js.map +1 -0
  464. package/dist/rbac/permission-repository.d.ts +100 -0
  465. package/dist/rbac/permission-repository.d.ts.map +1 -0
  466. package/dist/rbac/permission-repository.js +190 -0
  467. package/dist/rbac/permission-repository.js.map +1 -0
  468. package/dist/rbac/permission-service.d.ts +85 -0
  469. package/dist/rbac/permission-service.d.ts.map +1 -0
  470. package/dist/rbac/permission-service.js +179 -0
  471. package/dist/rbac/permission-service.js.map +1 -0
  472. package/dist/rbac/role-repository.d.ts +104 -0
  473. package/dist/rbac/role-repository.d.ts.map +1 -0
  474. package/dist/rbac/role-repository.js +202 -0
  475. package/dist/rbac/role-repository.js.map +1 -0
  476. package/dist/rbac/role-service.d.ts +111 -0
  477. package/dist/rbac/role-service.d.ts.map +1 -0
  478. package/dist/rbac/role-service.js +256 -0
  479. package/dist/rbac/role-service.js.map +1 -0
  480. package/dist/rbac/slugs.d.ts +116 -0
  481. package/dist/rbac/slugs.d.ts.map +1 -0
  482. package/dist/rbac/slugs.js +178 -0
  483. package/dist/rbac/slugs.js.map +1 -0
  484. package/dist/rbac/types.d.ts +187 -0
  485. package/dist/rbac/types.d.ts.map +1 -0
  486. package/dist/rbac/types.js +75 -0
  487. package/dist/rbac/types.js.map +1 -0
  488. package/dist/rbac/user-role-service.d.ts +101 -0
  489. package/dist/rbac/user-role-service.d.ts.map +1 -0
  490. package/dist/rbac/user-role-service.js +166 -0
  491. package/dist/rbac/user-role-service.js.map +1 -0
  492. package/dist/routes/applications.d.ts +40 -0
  493. package/dist/routes/applications.d.ts.map +1 -0
  494. package/dist/routes/applications.js +284 -0
  495. package/dist/routes/applications.js.map +1 -0
  496. package/dist/routes/audit.d.ts +31 -0
  497. package/dist/routes/audit.d.ts.map +1 -0
  498. package/dist/routes/audit.js +140 -0
  499. package/dist/routes/audit.js.map +1 -0
  500. package/dist/routes/branding.d.ts +17 -0
  501. package/dist/routes/branding.d.ts.map +1 -0
  502. package/dist/routes/branding.js +104 -0
  503. package/dist/routes/branding.js.map +1 -0
  504. package/dist/routes/bulk.d.ts +37 -0
  505. package/dist/routes/bulk.d.ts.map +1 -0
  506. package/dist/routes/bulk.js +94 -0
  507. package/dist/routes/bulk.js.map +1 -0
  508. package/dist/routes/clients.d.ts +44 -0
  509. package/dist/routes/clients.d.ts.map +1 -0
  510. package/dist/routes/clients.js +353 -0
  511. package/dist/routes/clients.js.map +1 -0
  512. package/dist/routes/config.d.ts +35 -0
  513. package/dist/routes/config.d.ts.map +1 -0
  514. package/dist/routes/config.js +115 -0
  515. package/dist/routes/config.js.map +1 -0
  516. package/dist/routes/custom-claims.d.ts +38 -0
  517. package/dist/routes/custom-claims.d.ts.map +1 -0
  518. package/dist/routes/custom-claims.js +208 -0
  519. package/dist/routes/custom-claims.js.map +1 -0
  520. package/dist/routes/exports.d.ts +21 -0
  521. package/dist/routes/exports.d.ts.map +1 -0
  522. package/dist/routes/exports.js +98 -0
  523. package/dist/routes/exports.js.map +1 -0
  524. package/dist/routes/imports.d.ts +18 -0
  525. package/dist/routes/imports.d.ts.map +1 -0
  526. package/dist/routes/imports.js +72 -0
  527. package/dist/routes/imports.js.map +1 -0
  528. package/dist/routes/interactions.d.ts +111 -0
  529. package/dist/routes/interactions.d.ts.map +1 -0
  530. package/dist/routes/interactions.js +1074 -0
  531. package/dist/routes/interactions.js.map +1 -0
  532. package/dist/routes/invitation.d.ts +31 -0
  533. package/dist/routes/invitation.d.ts.map +1 -0
  534. package/dist/routes/invitation.js +342 -0
  535. package/dist/routes/invitation.js.map +1 -0
  536. package/dist/routes/keys.d.ts +28 -0
  537. package/dist/routes/keys.d.ts.map +1 -0
  538. package/dist/routes/keys.js +91 -0
  539. package/dist/routes/keys.js.map +1 -0
  540. package/dist/routes/magic-link.d.ts +43 -0
  541. package/dist/routes/magic-link.d.ts.map +1 -0
  542. package/dist/routes/magic-link.js +264 -0
  543. package/dist/routes/magic-link.js.map +1 -0
  544. package/dist/routes/organizations.d.ts +38 -0
  545. package/dist/routes/organizations.d.ts.map +1 -0
  546. package/dist/routes/organizations.js +347 -0
  547. package/dist/routes/organizations.js.map +1 -0
  548. package/dist/routes/password-reset.d.ts +65 -0
  549. package/dist/routes/password-reset.d.ts.map +1 -0
  550. package/dist/routes/password-reset.js +493 -0
  551. package/dist/routes/password-reset.js.map +1 -0
  552. package/dist/routes/permissions.d.ts +33 -0
  553. package/dist/routes/permissions.d.ts.map +1 -0
  554. package/dist/routes/permissions.js +166 -0
  555. package/dist/routes/permissions.js.map +1 -0
  556. package/dist/routes/roles.d.ts +37 -0
  557. package/dist/routes/roles.d.ts.map +1 -0
  558. package/dist/routes/roles.js +222 -0
  559. package/dist/routes/roles.js.map +1 -0
  560. package/dist/routes/sessions.d.ts +37 -0
  561. package/dist/routes/sessions.d.ts.map +1 -0
  562. package/dist/routes/sessions.js +121 -0
  563. package/dist/routes/sessions.js.map +1 -0
  564. package/dist/routes/stats.d.ts +28 -0
  565. package/dist/routes/stats.d.ts.map +1 -0
  566. package/dist/routes/stats.js +65 -0
  567. package/dist/routes/stats.js.map +1 -0
  568. package/dist/routes/two-factor-admin.d.ts +54 -0
  569. package/dist/routes/two-factor-admin.d.ts.map +1 -0
  570. package/dist/routes/two-factor-admin.js +344 -0
  571. package/dist/routes/two-factor-admin.js.map +1 -0
  572. package/dist/routes/two-factor.d.ts +31 -0
  573. package/dist/routes/two-factor.d.ts.map +1 -0
  574. package/dist/routes/two-factor.js +595 -0
  575. package/dist/routes/two-factor.js.map +1 -0
  576. package/dist/routes/user-roles.d.ts +33 -0
  577. package/dist/routes/user-roles.d.ts.map +1 -0
  578. package/dist/routes/user-roles.js +129 -0
  579. package/dist/routes/user-roles.js.map +1 -0
  580. package/dist/routes/users.d.ts +61 -0
  581. package/dist/routes/users.d.ts.map +1 -0
  582. package/dist/routes/users.js +868 -0
  583. package/dist/routes/users.js.map +1 -0
  584. package/dist/security/decision-context.d.ts +52 -0
  585. package/dist/security/decision-context.d.ts.map +1 -0
  586. package/dist/security/decision-context.js +150 -0
  587. package/dist/security/decision-context.js.map +1 -0
  588. package/dist/security/decision-event.d.ts +128 -0
  589. package/dist/security/decision-event.d.ts.map +1 -0
  590. package/dist/security/decision-event.js +225 -0
  591. package/dist/security/decision-event.js.map +1 -0
  592. package/dist/security/transport-decision.d.ts +6 -0
  593. package/dist/security/transport-decision.d.ts.map +1 -0
  594. package/dist/security/transport-decision.js +37 -0
  595. package/dist/security/transport-decision.js.map +1 -0
  596. package/dist/server.d.ts +50 -0
  597. package/dist/server.d.ts.map +1 -0
  598. package/dist/server.js +491 -0
  599. package/dist/server.js.map +1 -0
  600. package/dist/two-factor/cache.d.ts +47 -0
  601. package/dist/two-factor/cache.d.ts.map +1 -0
  602. package/dist/two-factor/cache.js +122 -0
  603. package/dist/two-factor/cache.js.map +1 -0
  604. package/dist/two-factor/crypto.d.ts +41 -0
  605. package/dist/two-factor/crypto.d.ts.map +1 -0
  606. package/dist/two-factor/crypto.js +94 -0
  607. package/dist/two-factor/crypto.js.map +1 -0
  608. package/dist/two-factor/errors.d.ts +82 -0
  609. package/dist/two-factor/errors.d.ts.map +1 -0
  610. package/dist/two-factor/errors.js +112 -0
  611. package/dist/two-factor/errors.js.map +1 -0
  612. package/dist/two-factor/index.d.ts +18 -0
  613. package/dist/two-factor/index.d.ts.map +1 -0
  614. package/dist/two-factor/index.js +25 -0
  615. package/dist/two-factor/index.js.map +1 -0
  616. package/dist/two-factor/otp.d.ts +43 -0
  617. package/dist/two-factor/otp.d.ts.map +1 -0
  618. package/dist/two-factor/otp.js +57 -0
  619. package/dist/two-factor/otp.js.map +1 -0
  620. package/dist/two-factor/recovery.d.ts +45 -0
  621. package/dist/two-factor/recovery.d.ts.map +1 -0
  622. package/dist/two-factor/recovery.js +104 -0
  623. package/dist/two-factor/recovery.js.map +1 -0
  624. package/dist/two-factor/repository.d.ts +156 -0
  625. package/dist/two-factor/repository.d.ts.map +1 -0
  626. package/dist/two-factor/repository.js +251 -0
  627. package/dist/two-factor/repository.js.map +1 -0
  628. package/dist/two-factor/service.d.ts +232 -0
  629. package/dist/two-factor/service.d.ts.map +1 -0
  630. package/dist/two-factor/service.js +599 -0
  631. package/dist/two-factor/service.js.map +1 -0
  632. package/dist/two-factor/totp.d.ts +57 -0
  633. package/dist/two-factor/totp.d.ts.map +1 -0
  634. package/dist/two-factor/totp.js +96 -0
  635. package/dist/two-factor/totp.js.map +1 -0
  636. package/dist/two-factor/types.d.ts +152 -0
  637. package/dist/two-factor/types.d.ts.map +1 -0
  638. package/dist/two-factor/types.js +64 -0
  639. package/dist/two-factor/types.js.map +1 -0
  640. package/dist/users/cache.d.ts +49 -0
  641. package/dist/users/cache.d.ts.map +1 -0
  642. package/dist/users/cache.js +140 -0
  643. package/dist/users/cache.js.map +1 -0
  644. package/dist/users/claims.d.ts +67 -0
  645. package/dist/users/claims.d.ts.map +1 -0
  646. package/dist/users/claims.js +104 -0
  647. package/dist/users/claims.js.map +1 -0
  648. package/dist/users/errors.d.ts +25 -0
  649. package/dist/users/errors.d.ts.map +1 -0
  650. package/dist/users/errors.js +31 -0
  651. package/dist/users/errors.js.map +1 -0
  652. package/dist/users/gdpr.d.ts +110 -0
  653. package/dist/users/gdpr.d.ts.map +1 -0
  654. package/dist/users/gdpr.js +211 -0
  655. package/dist/users/gdpr.js.map +1 -0
  656. package/dist/users/index.d.ts +20 -0
  657. package/dist/users/index.d.ts.map +1 -0
  658. package/dist/users/index.js +19 -0
  659. package/dist/users/index.js.map +1 -0
  660. package/dist/users/password.d.ts +85 -0
  661. package/dist/users/password.d.ts.map +1 -0
  662. package/dist/users/password.js +138 -0
  663. package/dist/users/password.js.map +1 -0
  664. package/dist/users/repository.d.ts +263 -0
  665. package/dist/users/repository.d.ts.map +1 -0
  666. package/dist/users/repository.js +499 -0
  667. package/dist/users/repository.js.map +1 -0
  668. package/dist/users/service.d.ts +299 -0
  669. package/dist/users/service.d.ts.map +1 -0
  670. package/dist/users/service.js +698 -0
  671. package/dist/users/service.js.map +1 -0
  672. package/dist/users/types.d.ts +220 -0
  673. package/dist/users/types.d.ts.map +1 -0
  674. package/dist/users/types.js +77 -0
  675. package/dist/users/types.js.map +1 -0
  676. package/locales/default/en/common.json +10 -0
  677. package/locales/default/en/consent.json +13 -0
  678. package/locales/default/en/emails.json +17 -0
  679. package/locales/default/en/errors.json +21 -0
  680. package/locales/default/en/forgot-password.json +11 -0
  681. package/locales/default/en/invitation.json +18 -0
  682. package/locales/default/en/login.json +17 -0
  683. package/locales/default/en/logout.json +9 -0
  684. package/locales/default/en/magic-link.json +12 -0
  685. package/locales/default/en/reset-password.json +16 -0
  686. package/locales/default/en/two-factor.json +29 -0
  687. package/migrations/.gitkeep +0 -0
  688. package/migrations/001_extensions.sql +22 -0
  689. package/migrations/002_organizations.sql +43 -0
  690. package/migrations/003_applications.sql +50 -0
  691. package/migrations/004_clients.sql +74 -0
  692. package/migrations/005_users.sql +119 -0
  693. package/migrations/006_roles_permissions.sql +80 -0
  694. package/migrations/007_custom_claims.sql +55 -0
  695. package/migrations/008_config.sql +51 -0
  696. package/migrations/009_audit_log.sql +31 -0
  697. package/migrations/010_oidc_adapter.sql +34 -0
  698. package/migrations/011_seed.sql +53 -0
  699. package/migrations/012_two_factor.sql +88 -0
  700. package/migrations/013_client_secret_sha256.sql +22 -0
  701. package/migrations/014_login_methods.sql +34 -0
  702. package/migrations/015_signing_key_encryption.sql +20 -0
  703. package/migrations/016_failed_login_count.sql +27 -0
  704. package/migrations/017_audit_retention.sql +11 -0
  705. package/migrations/018_admin_api_enhancements.sql +78 -0
  706. package/migrations/019_invitation_details.sql +27 -0
  707. package/migrations/020_two_factor_admin_permission.sql +108 -0
  708. package/migrations/021_auth_recovery_jobs.sql +74 -0
  709. package/migrations/022_recovery_artifact_ownership.sql +25 -0
  710. package/migrations/023_magic_link_authority.sql +39 -0
  711. package/package.json +106 -0
  712. package/templates/default/emails/invitation.hbs +39 -0
  713. package/templates/default/emails/invitation.txt.hbs +18 -0
  714. package/templates/default/emails/magic-link.hbs +30 -0
  715. package/templates/default/emails/magic-link.txt.hbs +11 -0
  716. package/templates/default/emails/otp-code.hbs +31 -0
  717. package/templates/default/emails/otp-code.txt.hbs +15 -0
  718. package/templates/default/emails/password-changed.hbs +24 -0
  719. package/templates/default/emails/password-changed.txt.hbs +7 -0
  720. package/templates/default/emails/password-reset.hbs +30 -0
  721. package/templates/default/emails/password-reset.txt.hbs +11 -0
  722. package/templates/default/emails/welcome.hbs +25 -0
  723. package/templates/default/emails/welcome.txt.hbs +9 -0
  724. package/templates/default/layouts/main.hbs +49 -0
  725. package/templates/default/pages/accept-invite.hbs +25 -0
  726. package/templates/default/pages/consent.hbs +27 -0
  727. package/templates/default/pages/error.hbs +15 -0
  728. package/templates/default/pages/forgot-password.hbs +21 -0
  729. package/templates/default/pages/invite-expired.hbs +6 -0
  730. package/templates/default/pages/invite-success.hbs +9 -0
  731. package/templates/default/pages/login.hbs +108 -0
  732. package/templates/default/pages/logout-success.hbs +5 -0
  733. package/templates/default/pages/logout.hbs +24 -0
  734. package/templates/default/pages/magic-link-sent.hbs +10 -0
  735. package/templates/default/pages/magic-link-success.hbs +17 -0
  736. package/templates/default/pages/reset-password.hbs +20 -0
  737. package/templates/default/pages/reset-success.hbs +9 -0
  738. package/templates/default/pages/two-factor-setup.hbs +65 -0
  739. package/templates/default/pages/two-factor-verify.hbs +77 -0
  740. package/templates/default/partials/flash-messages.hbs +10 -0
  741. package/templates/default/partials/footer.hbs +4 -0
  742. package/templates/default/partials/header.hbs +8 -0
@@ -0,0 +1,267 @@
1
+ /**
2
+ * OIDC CORS middleware — pre-sets CORS headers at the outer Koa level.
3
+ *
4
+ * Solves a fundamental issue with node-oidc-provider's CORS handling:
5
+ * the provider uses @koa/cors with `keepHeadersOnError: false`, which
6
+ * means CORS headers are stripped from error responses (e.g., 400 from
7
+ * the token endpoint). SPAs that exchange authorization codes or refresh
8
+ * tokens via cross-origin fetch() cannot read error responses, breaking
9
+ * error handling in browser-based OIDC flows.
10
+ *
11
+ * How this middleware fixes it:
12
+ *
13
+ * 1. It sets `Access-Control-Allow-Origin` and related headers BEFORE
14
+ * the request enters oidc-provider's internal Koa context.
15
+ *
16
+ * 2. The provider's `cors.js` middleware detects existing `access-control-*`
17
+ * headers and SKIPS its own CORS handling entirely (see
18
+ * node_modules/oidc-provider/lib/shared/cors.js lines 32-37).
19
+ *
20
+ * 3. Because the headers are set at the outer Koa level and the provider
21
+ * doesn't touch them, they survive regardless of whether the OIDC
22
+ * endpoint succeeds or returns an error.
23
+ *
24
+ * Origin validation follows the same two-tier strategy as `oidc-cors.ts`:
25
+ * - In development mode: all origins are allowed.
26
+ * - In production: the client's `allowed_origins` and `redirect_uris`
27
+ * are checked. The client is identified from the `client_id` body
28
+ * parameter (standard for token, revocation, and introspection
29
+ * endpoints). If no client_id is present or the client cannot be
30
+ * found, no CORS headers are set — the request proceeds but the
31
+ * browser will block the response (correct security behavior).
32
+ *
33
+ * Placement: mount in the `oidcRouter` (server.ts) AFTER the body parser
34
+ * (so `client_id` is available from `ctx.request.body`) but BEFORE the
35
+ * `clientSecretHash` middleware and the provider delegation handler.
36
+ *
37
+ * For OIDC endpoints that don't require client authentication (e.g.,
38
+ * JWKS, discovery), CORS is always allowed — these are public endpoints
39
+ * that any origin may access. The middleware detects these by path.
40
+ *
41
+ * @module middleware/oidc-preflight-cors
42
+ */
43
+ import { config } from '../config/index.js';
44
+ import { getClientByClientId } from '../clients/service.js';
45
+ import { getPool } from '../lib/database.js';
46
+ import { logger } from '../lib/logger.js';
47
+ // ---------------------------------------------------------------------------
48
+ // Public-endpoint path patterns — these are accessible without client auth
49
+ // and allow CORS from any origin (same as oidc-provider's "open" CORS).
50
+ // Paths are relative to the /:orgSlug prefix (after tenant resolution).
51
+ // ---------------------------------------------------------------------------
52
+ /** Paths that are publicly accessible and allow any CORS origin. */
53
+ const OPEN_CORS_PATHS = new Set([
54
+ '/jwks',
55
+ '/.well-known/openid-configuration',
56
+ '/.well-known/oauth-authorization-server',
57
+ ]);
58
+ /**
59
+ * Check if the request path (within the org scope) is a public endpoint
60
+ * that allows CORS from any origin.
61
+ *
62
+ * @param fullPath - The full request path (e.g., '/acme/jwks')
63
+ * @param orgSlug - The organization slug (e.g., 'acme')
64
+ * @returns true if the path is a public CORS endpoint
65
+ */
66
+ function isOpenCorsPath(fullPath, orgSlug) {
67
+ const subPath = fullPath.slice(`/${orgSlug}`.length);
68
+ return OPEN_CORS_PATHS.has(subPath);
69
+ }
70
+ /**
71
+ * Check if an origin is allowed for a given client by examining the
72
+ * client's `allowedOrigins` and `redirectUris` fields.
73
+ *
74
+ * This replicates the same logic as `oidc-cors.ts` but works with the
75
+ * Client domain object (from the service layer) rather than the OIDC
76
+ * provider's internal client metadata format.
77
+ *
78
+ * @param origin - The requesting origin (e.g., 'https://app.example.com')
79
+ * @param client - Client with allowedOrigins and redirectUris arrays
80
+ * @returns true if the origin is allowed
81
+ */
82
+ function isOriginAllowed(origin, client) {
83
+ // 1. Check explicit allowed_origins
84
+ if (client.allowedOrigins.includes(origin))
85
+ return true;
86
+ // 2. Derive origins from redirect_uris
87
+ for (const uri of client.redirectUris) {
88
+ try {
89
+ const redirectOrigin = new URL(uri).origin;
90
+ if (redirectOrigin !== 'null' && redirectOrigin === origin)
91
+ return true;
92
+ }
93
+ catch {
94
+ // Skip malformed URIs
95
+ }
96
+ }
97
+ return false;
98
+ }
99
+ /**
100
+ * Set standard CORS response headers for an allowed origin.
101
+ *
102
+ * @param ctx - Koa context
103
+ * @param origin - The allowed origin value
104
+ */
105
+ function setCorsHeaders(ctx, origin) {
106
+ ctx.set('Access-Control-Allow-Origin', origin);
107
+ ctx.set('Vary', 'Origin');
108
+ }
109
+ /**
110
+ * Set preflight-specific CORS response headers (in addition to the base
111
+ * headers set by `setCorsHeaders`).
112
+ *
113
+ * @param ctx - Koa context
114
+ */
115
+ function setPreflightHeaders(ctx) {
116
+ ctx.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
117
+ ctx.set('Access-Control-Allow-Headers', 'Authorization, Content-Type, DPoP');
118
+ ctx.set('Access-Control-Max-Age', '3600');
119
+ }
120
+ // ---------------------------------------------------------------------------
121
+ // Bearer token → clientId resolution
122
+ // ---------------------------------------------------------------------------
123
+ /**
124
+ * Extract the `clientId` from an opaque Bearer access token by looking
125
+ * up its record in PostgreSQL.
126
+ *
127
+ * node-oidc-provider stores opaque access tokens in the `oidc_payloads`
128
+ * table (via the PostgresAdapter) with `type = 'AccessToken'`. The token
129
+ * value sent by the client IS the `jti`, which is the `id` column in the
130
+ * table. The JSONB `payload` column includes a `clientId` field.
131
+ *
132
+ * NOTE: AccessToken is a long-lived model routed to PostgreSQL by the
133
+ * hybrid adapter factory (adapter-factory.ts). Short-lived models like
134
+ * Session and AuthorizationCode go to Redis, but AccessToken does NOT.
135
+ *
136
+ * This lookup is best-effort: if the token is missing, expired, or the
137
+ * database is unavailable, `null` is returned and CORS headers are not
138
+ * set. The actual token validation is still performed by the provider
139
+ * downstream.
140
+ *
141
+ * @param authHeader - The raw `Authorization` header value (e.g., 'Bearer abc123')
142
+ * @returns The clientId if resolved, or null
143
+ */
144
+ async function resolveClientIdFromBearerToken(authHeader) {
145
+ if (!authHeader)
146
+ return null;
147
+ // Extract the token value from "Bearer <token>"
148
+ const match = /^Bearer\s+(\S+)$/i.exec(authHeader);
149
+ if (!match)
150
+ return null;
151
+ const tokenValue = match[1];
152
+ try {
153
+ const pool = getPool();
154
+ const result = await pool.query(`SELECT payload->>'clientId' AS client_id
155
+ FROM oidc_payloads
156
+ WHERE id = $1 AND type = 'AccessToken'
157
+ AND (expires_at IS NULL OR expires_at > NOW())`, [tokenValue]);
158
+ if (result.rows.length === 0)
159
+ return null;
160
+ const clientId = result.rows[0].client_id;
161
+ return typeof clientId === 'string' && clientId.length > 0 ? clientId : null;
162
+ }
163
+ catch (err) {
164
+ // Database unavailable — graceful degradation.
165
+ // The provider will still validate the token; we just can't set
166
+ // CORS headers pre-emptively.
167
+ logger.debug({ err }, 'OIDC CORS: failed to resolve clientId from Bearer token');
168
+ return null;
169
+ }
170
+ }
171
+ // ---------------------------------------------------------------------------
172
+ // Middleware factory
173
+ // ---------------------------------------------------------------------------
174
+ /**
175
+ * Create the OIDC CORS middleware.
176
+ *
177
+ * Must be mounted in the oidcRouter AFTER the body parser (so
178
+ * `client_id` is available) but BEFORE `clientSecretHash` and the
179
+ * provider delegation handler.
180
+ *
181
+ * @returns Koa middleware that pre-sets CORS headers for OIDC routes
182
+ */
183
+ export function oidcPreflightCors() {
184
+ return async function oidcPreflightCorsMiddleware(ctx, next) {
185
+ const origin = ctx.get('Origin');
186
+ // No Origin header → not a CORS request (backend service, curl, etc.)
187
+ // Skip — no CORS headers needed.
188
+ if (!origin) {
189
+ return next();
190
+ }
191
+ const orgSlug = ctx.params?.orgSlug ?? '';
192
+ // -----------------------------------------------------------------------
193
+ // OPTIONS preflight — respond immediately, skip downstream middleware
194
+ // -----------------------------------------------------------------------
195
+ if (ctx.method === 'OPTIONS') {
196
+ // Dev: allow all origins
197
+ // Prod: allow preflight broadly — the actual request will do the
198
+ // full client-based check. If the actual request's origin is
199
+ // unauthorized, it won't have CORS headers and the browser will
200
+ // block the response. This is secure because the preflight itself
201
+ // doesn't grant any access — it only tells the browser that a
202
+ // subsequent actual request is permitted to be sent.
203
+ setCorsHeaders(ctx, origin);
204
+ setPreflightHeaders(ctx);
205
+ ctx.status = 204;
206
+ return;
207
+ }
208
+ // -----------------------------------------------------------------------
209
+ // Actual request (GET, POST, etc.) with Origin header
210
+ // -----------------------------------------------------------------------
211
+ // Public endpoints (jwks, discovery) allow any origin — no client check.
212
+ if (isOpenCorsPath(ctx.path, orgSlug)) {
213
+ setCorsHeaders(ctx, origin);
214
+ return next();
215
+ }
216
+ // Development mode: allow all origins for convenience.
217
+ if (config.nodeEnv === 'development') {
218
+ setCorsHeaders(ctx, origin);
219
+ return next();
220
+ }
221
+ // Production mode: client-based CORS check.
222
+ // Strategy: identify the client from one of two sources, then check
223
+ // whether the requesting origin is allowed for that client.
224
+ //
225
+ // 1. `client_id` in the body — token, revocation, introspection
226
+ // endpoints send client_id in the form-encoded body.
227
+ // 2. Bearer token in `Authorization` header — userinfo (/me) and
228
+ // other authenticated GET endpoints. The access token record in
229
+ // PostgreSQL contains the clientId that issued it.
230
+ //
231
+ // If neither source yields a client, no CORS headers are set (safe
232
+ // default: browser blocks the cross-origin response).
233
+ const body = ctx.request.body;
234
+ let clientId = typeof body?.client_id === 'string' && body.client_id.length > 0
235
+ ? body.client_id
236
+ : null;
237
+ // Fallback: extract clientId from a Bearer access token stored in PostgreSQL.
238
+ // This enables CORS for endpoints like /me (userinfo) where the only
239
+ // client identifier is embedded in the opaque access token record.
240
+ if (!clientId) {
241
+ clientId = await resolveClientIdFromBearerToken(ctx.get('Authorization'));
242
+ }
243
+ if (!clientId) {
244
+ // Can't identify client from body or Bearer token — skip CORS.
245
+ // The provider will process the request, but the browser blocks
246
+ // the cross-origin response. This is correct security behavior.
247
+ return next();
248
+ }
249
+ try {
250
+ const client = await getClientByClientId(clientId);
251
+ if (client && isOriginAllowed(origin, client)) {
252
+ setCorsHeaders(ctx, origin);
253
+ }
254
+ // If client not found or origin not allowed, don't set CORS headers.
255
+ // The provider processes the request normally, but the browser blocks
256
+ // the cross-origin response — correct security behavior.
257
+ }
258
+ catch (err) {
259
+ // Graceful degradation: if the client lookup fails (e.g., DB down),
260
+ // don't set CORS headers. The request proceeds but the browser
261
+ // blocks the response. This is the safe default.
262
+ logger.warn({ err, clientId, origin }, 'OIDC CORS: client lookup failed, CORS headers not set');
263
+ }
264
+ return next();
265
+ };
266
+ }
267
+ //# sourceMappingURL=oidc-preflight-cors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oidc-preflight-cors.js","sourceRoot":"","sources":["../../src/middleware/oidc-preflight-cors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,8EAA8E;AAC9E,2EAA2E;AAC3E,wEAAwE;AACxE,wEAAwE;AACxE,8EAA8E;AAE9E,oEAAoE;AACpE,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,OAAO;IACP,mCAAmC;IACnC,yCAAyC;CAC1C,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,SAAS,cAAc,CAAC,QAAgB,EAAE,OAAe;IACvD,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;IACrD,OAAO,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,eAAe,CACtB,MAAc,EACd,MAA4D;IAE5D,oCAAoC;IACpC,IAAI,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAExD,uCAAuC;IACvC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACtC,IAAI,CAAC;YACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;YAC3C,IAAI,cAAc,KAAK,MAAM,IAAI,cAAc,KAAK,MAAM;gBAAE,OAAO,IAAI,CAAC;QAC1E,CAAC;QAAC,MAAM,CAAC;YACP,sBAAsB;QACxB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,SAAS,cAAc,CACrB,GAAmD,EACnD,MAAc;IAEd,GAAG,CAAC,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;IAC/C,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;GAKG;AACH,SAAS,mBAAmB,CAC1B,GAAmD;IAEnD,GAAG,CAAC,GAAG,CAAC,8BAA8B,EAAE,oBAAoB,CAAC,CAAC;IAC9D,GAAG,CAAC,GAAG,CAAC,8BAA8B,EAAE,mCAAmC,CAAC,CAAC;IAC7E,GAAG,CAAC,GAAG,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED,8EAA8E;AAC9E,qCAAqC;AACrC,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,KAAK,UAAU,8BAA8B,CAAC,UAAkB;IAC9D,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE7B,gDAAgD;IAChD,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAE5B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAC7B;;;wDAGkD,EAClD,CAAC,UAAU,CAAC,CACb,CAAC;QAEF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAE1C,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1C,OAAO,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,+CAA+C;QAC/C,gEAAgE;QAChE,8BAA8B;QAC9B,MAAM,CAAC,KAAK,CACV,EAAE,GAAG,EAAE,EACP,yDAAyD,CAC1D,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,KAAK,UAAU,2BAA2B,CAAC,GAAG,EAAE,IAAI;QACzD,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEjC,sEAAsE;QACtE,iCAAiC;QACjC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC;QAE1C,0EAA0E;QAC1E,sEAAsE;QACtE,0EAA0E;QAC1E,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,yBAAyB;YACzB,iEAAiE;YACjE,6DAA6D;YAC7D,gEAAgE;YAChE,kEAAkE;YAClE,8DAA8D;YAC9D,qDAAqD;YACrD,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC5B,mBAAmB,CAAC,GAAG,CAAC,CAAC;YACzB,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,OAAO;QACT,CAAC;QAED,0EAA0E;QAC1E,sDAAsD;QACtD,0EAA0E;QAE1E,yEAAyE;QACzE,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;YACtC,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC5B,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,uDAAuD;QACvD,IAAI,MAAM,CAAC,OAAO,KAAK,aAAa,EAAE,CAAC;YACrC,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC5B,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,4CAA4C;QAC5C,oEAAoE;QACpE,4DAA4D;QAC5D,EAAE;QACF,kEAAkE;QAClE,0DAA0D;QAC1D,mEAAmE;QACnE,qEAAqE;QACrE,wDAAwD;QACxD,EAAE;QACF,mEAAmE;QACnE,sDAAsD;QACtD,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAA2C,CAAC;QACrE,IAAI,QAAQ,GACV,OAAO,IAAI,EAAE,SAAS,KAAK,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;YAC9D,CAAC,CAAC,IAAI,CAAC,SAAS;YAChB,CAAC,CAAC,IAAI,CAAC;QAEX,8EAA8E;QAC9E,qEAAqE;QACrE,mEAAmE;QACnE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,MAAM,8BAA8B,CAAC,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC;QAC5E,CAAC;QAED,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,+DAA+D;YAC/D,gEAAgE;YAChE,gEAAgE;YAChE,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAC;YACnD,IAAI,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;gBAC9C,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC9B,CAAC;YACD,qEAAqE;YACrE,sEAAsE;YACtE,yDAAyD;QAC3D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,oEAAoE;YACpE,+DAA+D;YAC/D,iDAAiD;YACjD,MAAM,CAAC,IAAI,CACT,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,EACzB,uDAAuD,CACxD,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,EAAE,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * prompt=login session-reset middleware.
3
+ *
4
+ * Fixes the "Something went wrong" dead-end on browser re-login (Bug #1).
5
+ *
6
+ * Root cause: a stale `_session` cookie from a previous login survives into a
7
+ * new `prompt=login` authorization flow. The provider rotates the session id
8
+ * during resume, so the interaction's recorded session uid no longer matches
9
+ * the live session uid → node-oidc-provider throws `SessionNotFound` and the
10
+ * user sees a terminal error. (Confirmed: the Redis Session record is present
11
+ * during the failure — this is NOT a Redis durability problem.)
12
+ *
13
+ * Fix: on an initial GET/POST authorize request whose `prompt` parameter
14
+ * contains `login`, clear the `_session` + `_session.sig` cookies BEFORE the
15
+ * provider runs. With no stale cookie, the provider mints a fresh session and
16
+ * there is no uid mismatch. The stale Redis Session record is left to expire on
17
+ * its own via TTL (AR-2, revised) — clearing the cookie is what fixes the bug.
18
+ *
19
+ * Design notes:
20
+ * - Only acts when `prompt` contains the `login` value (AR-3). Normal SSO /
21
+ * session-reuse logins are unaffected (AR-5).
22
+ * - Reads `prompt` from the query string. The CLI and standard browser RP flows
23
+ * use GET authorize with `prompt` in the query, so this covers the real flow
24
+ * without consuming the POST body stream the provider needs (PF-005).
25
+ * - Cookie clearing is signing-free: we expire both `_session` and
26
+ * `_session.sig` explicitly. The outer Koa app does not set `app.keys`, so we
27
+ * must NOT rely on Koa's signed-cookie API here (PF-001/PF-002).
28
+ *
29
+ * @module middleware/prompt-login-reset
30
+ */
31
+ import type { Middleware } from 'koa';
32
+ import type Provider from 'oidc-provider';
33
+ /**
34
+ * Does the OIDC `prompt` parameter request a forced login?
35
+ *
36
+ * Per OIDC Core §3.1.2.1, `prompt` is a space-delimited list of values.
37
+ * Returns true only when `login` is one of those values (exact token match —
38
+ * not a substring, so `logins` or `login_hint` values do not match).
39
+ *
40
+ * @param prompt - The raw `prompt` parameter value (or undefined)
41
+ * @returns true if `login` is present among the space-delimited values
42
+ */
43
+ export declare function promptHasLogin(prompt: string | undefined | null): boolean;
44
+ /**
45
+ * Is this request the INITIAL org-scoped authorize endpoint?
46
+ *
47
+ * Matches `GET`/`POST` `/{orgSlug}/auth` (with optional trailing slash) but
48
+ * NOT the resume route `/{orgSlug}/auth/{uid}` and not other OIDC endpoints
49
+ * (`/token`, `/jwks`, etc.). The resume route must be excluded because the
50
+ * session-mismatch happens there — we reset on the *initial* authorize so the
51
+ * interaction binds to a fresh session.
52
+ *
53
+ * @param method - HTTP method
54
+ * @param path - Request path (outer Koa path, includes the org slug)
55
+ * @returns true if this is the initial authorize endpoint
56
+ */
57
+ export declare function isInitialAuthorize(method: string, path: string): boolean;
58
+ /**
59
+ * Clear the OIDC session cookie pair (`_session` + `_session.sig`).
60
+ *
61
+ * Expires BOTH cookie names at path `/` with attributes matching how the
62
+ * provider wrote them (httpOnly, sameSite=lax, secure per issuer scheme). This
63
+ * is intentionally signing-free: it sets each cookie to an expired value
64
+ * directly, so it works regardless of whether `app.keys` is configured on the
65
+ * Koa app (the outer Porta app does not set it). (PF-001/PF-002, AR-2)
66
+ *
67
+ * @param ctx - Koa context (outer app context or provider ctx — both work)
68
+ * @param sessionCookieName - The provider's session cookie name (e.g. `_session`)
69
+ */
70
+ export declare function clearSessionCookies(ctx: any, sessionCookieName: string): void;
71
+ /**
72
+ * Strip the OIDC session cookie pair from the INBOUND request header.
73
+ *
74
+ * This is the critical half of the fix. node-oidc-provider is invoked via
75
+ * `provider.callback()(ctx.req, ctx.res)` and reads the session cookie from the
76
+ * raw inbound request (`ctx.req.headers.cookie`) — NOT from anything we write to
77
+ * the response. Clearing the response cookie (via `clearSessionCookies`) only
78
+ * tells the *browser* to drop the cookie on *future* requests; it does nothing
79
+ * for the current request the provider is about to process.
80
+ *
81
+ * To prevent the provider from seeing the stale `_session` during THIS request
82
+ * (and thus hitting the session-id-rotation `SessionNotFound`), we must remove
83
+ * the session cookie pair from `ctx.req.headers.cookie` before calling `next()`.
84
+ *
85
+ * Removes any cookie whose name is exactly `sessionCookieName` or begins with
86
+ * `${sessionCookieName}.` (covers `_session.sig`, `_session.legacy`,
87
+ * `_session.legacy.sig`). All other cookies are preserved unchanged.
88
+ *
89
+ * @param ctx - Koa context (its `ctx.req` is the same raw req the provider reads)
90
+ * @param sessionCookieName - The provider's session cookie name (e.g. `_session`)
91
+ */
92
+ export declare function stripSessionCookiesFromRequest(ctx: any, sessionCookieName: string): void;
93
+ /**
94
+ * Create the prompt=login session-reset middleware.
95
+ *
96
+ * Mounted in `src/server.ts` BEFORE the `/:orgSlug/*` OIDC router so it runs on
97
+ * the outer Koa context before the provider processes the authorize request.
98
+ *
99
+ * @param provider - OIDC provider instance (used only for the session cookie name)
100
+ * @returns Koa middleware
101
+ */
102
+ export declare function promptLoginReset(provider: Provider): Middleware;
103
+ //# sourceMappingURL=prompt-login-reset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-login-reset.d.ts","sourceRoot":"","sources":["../../src/middleware/prompt-login-reset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAS1C;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAGzE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKxE;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAEjC,GAAG,EAAE,GAAG,EACR,iBAAiB,EAAE,MAAM,GACxB,IAAI,CAiBN;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,8BAA8B,CAE5C,GAAG,EAAE,GAAG,EACR,iBAAiB,EAAE,MAAM,GACxB,IAAI,CAoBN;AAMD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,UAAU,CAqD/D"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * prompt=login session-reset middleware.
3
+ *
4
+ * Fixes the "Something went wrong" dead-end on browser re-login (Bug #1).
5
+ *
6
+ * Root cause: a stale `_session` cookie from a previous login survives into a
7
+ * new `prompt=login` authorization flow. The provider rotates the session id
8
+ * during resume, so the interaction's recorded session uid no longer matches
9
+ * the live session uid → node-oidc-provider throws `SessionNotFound` and the
10
+ * user sees a terminal error. (Confirmed: the Redis Session record is present
11
+ * during the failure — this is NOT a Redis durability problem.)
12
+ *
13
+ * Fix: on an initial GET/POST authorize request whose `prompt` parameter
14
+ * contains `login`, clear the `_session` + `_session.sig` cookies BEFORE the
15
+ * provider runs. With no stale cookie, the provider mints a fresh session and
16
+ * there is no uid mismatch. The stale Redis Session record is left to expire on
17
+ * its own via TTL (AR-2, revised) — clearing the cookie is what fixes the bug.
18
+ *
19
+ * Design notes:
20
+ * - Only acts when `prompt` contains the `login` value (AR-3). Normal SSO /
21
+ * session-reuse logins are unaffected (AR-5).
22
+ * - Reads `prompt` from the query string. The CLI and standard browser RP flows
23
+ * use GET authorize with `prompt` in the query, so this covers the real flow
24
+ * without consuming the POST body stream the provider needs (PF-005).
25
+ * - Cookie clearing is signing-free: we expire both `_session` and
26
+ * `_session.sig` explicitly. The outer Koa app does not set `app.keys`, so we
27
+ * must NOT rely on Koa's signed-cookie API here (PF-001/PF-002).
28
+ *
29
+ * @module middleware/prompt-login-reset
30
+ */
31
+ import { config } from '../config/index.js';
32
+ import { logger } from '../lib/logger.js';
33
+ import { writeAuditLog } from '../lib/audit-log.js';
34
+ // ---------------------------------------------------------------------------
35
+ // Pure helpers (exported for testing)
36
+ // ---------------------------------------------------------------------------
37
+ /**
38
+ * Does the OIDC `prompt` parameter request a forced login?
39
+ *
40
+ * Per OIDC Core §3.1.2.1, `prompt` is a space-delimited list of values.
41
+ * Returns true only when `login` is one of those values (exact token match —
42
+ * not a substring, so `logins` or `login_hint` values do not match).
43
+ *
44
+ * @param prompt - The raw `prompt` parameter value (or undefined)
45
+ * @returns true if `login` is present among the space-delimited values
46
+ */
47
+ export function promptHasLogin(prompt) {
48
+ if (!prompt)
49
+ return false;
50
+ return prompt.split(' ').filter(Boolean).includes('login');
51
+ }
52
+ /**
53
+ * Is this request the INITIAL org-scoped authorize endpoint?
54
+ *
55
+ * Matches `GET`/`POST` `/{orgSlug}/auth` (with optional trailing slash) but
56
+ * NOT the resume route `/{orgSlug}/auth/{uid}` and not other OIDC endpoints
57
+ * (`/token`, `/jwks`, etc.). The resume route must be excluded because the
58
+ * session-mismatch happens there — we reset on the *initial* authorize so the
59
+ * interaction binds to a fresh session.
60
+ *
61
+ * @param method - HTTP method
62
+ * @param path - Request path (outer Koa path, includes the org slug)
63
+ * @returns true if this is the initial authorize endpoint
64
+ */
65
+ export function isInitialAuthorize(method, path) {
66
+ if (method !== 'GET' && method !== 'POST')
67
+ return false;
68
+ // ^/{slug}/auth or /{slug}/auth/ — exactly one path segment before /auth,
69
+ // and nothing (or only a trailing slash) after.
70
+ return /^\/[^/]+\/auth\/?$/.test(path);
71
+ }
72
+ // ---------------------------------------------------------------------------
73
+ // Cookie clearing (signing-free, shared)
74
+ // ---------------------------------------------------------------------------
75
+ /**
76
+ * Clear the OIDC session cookie pair (`_session` + `_session.sig`).
77
+ *
78
+ * Expires BOTH cookie names at path `/` with attributes matching how the
79
+ * provider wrote them (httpOnly, sameSite=lax, secure per issuer scheme). This
80
+ * is intentionally signing-free: it sets each cookie to an expired value
81
+ * directly, so it works regardless of whether `app.keys` is configured on the
82
+ * Koa app (the outer Porta app does not set it). (PF-001/PF-002, AR-2)
83
+ *
84
+ * @param ctx - Koa context (outer app context or provider ctx — both work)
85
+ * @param sessionCookieName - The provider's session cookie name (e.g. `_session`)
86
+ */
87
+ export function clearSessionCookies(
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ ctx, sessionCookieName) {
90
+ const secure = config.issuerBaseUrl.startsWith('https://');
91
+ const opts = {
92
+ path: '/',
93
+ httpOnly: true,
94
+ sameSite: 'lax',
95
+ secure,
96
+ // Do NOT use signed: true — the outer app has no app.keys.
97
+ signed: false,
98
+ // Expire immediately.
99
+ expires: new Date(0),
100
+ maxAge: 0,
101
+ };
102
+ // Clear the main cookie and its signature companion explicitly.
103
+ ctx.cookies.set(sessionCookieName, null, opts);
104
+ ctx.cookies.set(`${sessionCookieName}.sig`, null, opts);
105
+ }
106
+ /**
107
+ * Strip the OIDC session cookie pair from the INBOUND request header.
108
+ *
109
+ * This is the critical half of the fix. node-oidc-provider is invoked via
110
+ * `provider.callback()(ctx.req, ctx.res)` and reads the session cookie from the
111
+ * raw inbound request (`ctx.req.headers.cookie`) — NOT from anything we write to
112
+ * the response. Clearing the response cookie (via `clearSessionCookies`) only
113
+ * tells the *browser* to drop the cookie on *future* requests; it does nothing
114
+ * for the current request the provider is about to process.
115
+ *
116
+ * To prevent the provider from seeing the stale `_session` during THIS request
117
+ * (and thus hitting the session-id-rotation `SessionNotFound`), we must remove
118
+ * the session cookie pair from `ctx.req.headers.cookie` before calling `next()`.
119
+ *
120
+ * Removes any cookie whose name is exactly `sessionCookieName` or begins with
121
+ * `${sessionCookieName}.` (covers `_session.sig`, `_session.legacy`,
122
+ * `_session.legacy.sig`). All other cookies are preserved unchanged.
123
+ *
124
+ * @param ctx - Koa context (its `ctx.req` is the same raw req the provider reads)
125
+ * @param sessionCookieName - The provider's session cookie name (e.g. `_session`)
126
+ */
127
+ export function stripSessionCookiesFromRequest(
128
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
129
+ ctx, sessionCookieName) {
130
+ const header = ctx.req?.headers?.cookie;
131
+ if (!header)
132
+ return;
133
+ const prefix = `${sessionCookieName}.`;
134
+ const kept = header
135
+ .split(';')
136
+ .map((pair) => pair.trim())
137
+ .filter((pair) => {
138
+ if (!pair)
139
+ return false;
140
+ const eq = pair.indexOf('=');
141
+ const name = (eq === -1 ? pair : pair.slice(0, eq)).trim();
142
+ return name !== sessionCookieName && !name.startsWith(prefix);
143
+ });
144
+ if (kept.length === 0) {
145
+ delete ctx.req.headers.cookie;
146
+ }
147
+ else {
148
+ ctx.req.headers.cookie = kept.join('; ');
149
+ }
150
+ }
151
+ // ---------------------------------------------------------------------------
152
+ // Middleware factory
153
+ // ---------------------------------------------------------------------------
154
+ /**
155
+ * Create the prompt=login session-reset middleware.
156
+ *
157
+ * Mounted in `src/server.ts` BEFORE the `/:orgSlug/*` OIDC router so it runs on
158
+ * the outer Koa context before the provider processes the authorize request.
159
+ *
160
+ * @param provider - OIDC provider instance (used only for the session cookie name)
161
+ * @returns Koa middleware
162
+ */
163
+ export function promptLoginReset(provider) {
164
+ // Resolve the session cookie name once (e.g. '_session'). `cookieName` is a
165
+ // runtime method on the provider that is not present in the TypeScript types,
166
+ // so we access it via a narrow cast and fall back to the provider default
167
+ // (`_session`) if it is unavailable.
168
+ const providerWithCookieName = provider;
169
+ const sessionCookieName = typeof providerWithCookieName.cookieName === 'function'
170
+ ? providerWithCookieName.cookieName('session')
171
+ : '_session';
172
+ return async (ctx, next) => {
173
+ if (!isInitialAuthorize(ctx.method, ctx.path)) {
174
+ return next();
175
+ }
176
+ const prompt = ctx.query.prompt;
177
+ const promptValue = Array.isArray(prompt) ? prompt.join(' ') : prompt;
178
+ if (!promptHasLogin(promptValue)) {
179
+ return next();
180
+ }
181
+ // Force a clean slate. TWO actions are required:
182
+ //
183
+ // 1. Strip the session cookie pair from the INBOUND request header so the
184
+ // provider — invoked this same request via `provider.callback()(ctx.req,
185
+ // ctx.res)`, which reads `ctx.req.headers.cookie` — does NOT see the
186
+ // stale `_session` and cannot hit the session-id-rotation
187
+ // `SessionNotFound`. This is the half that actually fixes the bug.
188
+ // 2. Clear the response cookie pair so the browser drops the stale cookie
189
+ // for future requests too.
190
+ stripSessionCookiesFromRequest(ctx, sessionCookieName);
191
+ clearSessionCookies(ctx, sessionCookieName);
192
+ logger.info({ path: ctx.path }, 'prompt=login: cleared session cookies for forced re-authentication');
193
+ // Best-effort audit (no sensitive data). Fire-and-forget pattern matches
194
+ // writeAuditLog's own contract (it never throws).
195
+ writeAuditLog({
196
+ eventType: 'auth.prompt_login.session_reset',
197
+ eventCategory: 'authentication',
198
+ description: 'Session cookies cleared on prompt=login (forced re-authentication)',
199
+ ipAddress: ctx.ip,
200
+ });
201
+ return next();
202
+ };
203
+ }
204
+ //# sourceMappingURL=prompt-login-reset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-login-reset.js","sourceRoot":"","sources":["../../src/middleware/prompt-login-reset.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Readiness probe handler — GET /ready.
3
+ *
4
+ * Separate from /health (liveness): /health confirms the server process
5
+ * is alive; /ready confirms the server can actually serve requests by
6
+ * checking that both PostgreSQL and Redis are reachable within a timeout.
7
+ *
8
+ * Kubernetes / ECS maps:
9
+ * - livenessProbe → GET /health
10
+ * - readinessProbe → GET /ready
11
+ *
12
+ * Returns 200 + { status: 'ready', checks } when both backends are healthy,
13
+ * or 503 + { status: 'not_ready', checks } when either is degraded.
14
+ */
15
+ import type { Middleware } from 'koa';
16
+ /**
17
+ * Create the readiness probe middleware.
18
+ *
19
+ * Both DB and Redis are checked concurrently with individual timeouts.
20
+ * A single failure makes the overall probe return 503.
21
+ */
22
+ export declare function readyHandler(): Middleware;
23
+ //# sourceMappingURL=ready.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ready.d.ts","sourceRoot":"","sources":["../../src/middleware/ready.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAwBtC;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,UAAU,CA6BzC"}