@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,31 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <style>
7
+ body { font-family: system-ui, sans-serif; margin: 0; padding: 0; background: #f5f5f5; }
8
+ .wrapper { max-width: 560px; margin: 0 auto; padding: 40px 20px; }
9
+ .card { background: white; border-radius: 8px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
10
+ .code-box { text-align: center; margin: 24px 0; padding: 16px; background: #f3f4f6; border-radius: 8px; }
11
+ .code { font-size: 32px; font-weight: 700; letter-spacing: 6px; color: {{branding.primaryColor}}; font-family: monospace; }
12
+ .footer { text-align: center; padding: 16px; color: #6b7280; font-size: 12px; }
13
+ </style>
14
+ </head>
15
+ <body>
16
+ <div class="wrapper">
17
+ <div class="card">
18
+ {{#if branding.logoUrl}}<img src="{{branding.logoUrl}}" alt="{{branding.companyName}}" style="max-height: 40px; margin-bottom: 16px;">{{/if}}
19
+ <h1 style="font-size: 20px; margin: 0 0 12px 0;">Your verification code</h1>
20
+ <p>Hi {{userName}},</p>
21
+ <p>Use the following code to complete your sign-in. This code expires in {{expiresMinutes}} minutes.</p>
22
+ <div class="code-box">
23
+ <div class="code">{{code}}</div>
24
+ </div>
25
+ <p style="color: #6b7280; font-size: 13px;">If you didn't request this code, someone may be trying to access your account. You can safely ignore this email.</p>
26
+ <p style="color: #6b7280; font-size: 13px;">Do not share this code with anyone. {{orgName}} will never ask you for this code.</p>
27
+ </div>
28
+ <div class="footer">&copy; {{year}} {{branding.companyName}}</div>
29
+ </div>
30
+ </body>
31
+ </html>
@@ -0,0 +1,15 @@
1
+ Your verification code
2
+
3
+ Hi {{userName}},
4
+
5
+ Use the following code to complete your sign-in:
6
+
7
+ {{code}}
8
+
9
+ This code expires in {{expiresMinutes}} minutes.
10
+
11
+ If you didn't request this code, someone may be trying to access your account. You can safely ignore this email.
12
+
13
+ Do not share this code with anyone. {{orgName}} will never ask you for this code.
14
+
15
+ © {{year}} {{branding.companyName}}
@@ -0,0 +1,24 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <style>
7
+ body { font-family: system-ui, sans-serif; margin: 0; padding: 0; background: #f5f5f5; }
8
+ .wrapper { max-width: 560px; margin: 0 auto; padding: 40px 20px; }
9
+ .card { background: white; border-radius: 8px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
10
+ .footer { text-align: center; padding: 16px; color: #6b7280; font-size: 12px; }
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <div class="wrapper">
15
+ <div class="card">
16
+ {{#if branding.logoUrl}}<img src="{{branding.logoUrl}}" alt="{{branding.companyName}}" style="max-height: 40px; margin-bottom: 16px;">{{/if}}
17
+ <h1 style="font-size: 20px; margin: 0 0 12px 0;">Password changed</h1>
18
+ <p>Hi {{userName}},</p>
19
+ <p>Your password has been successfully changed. If you did not make this change, please contact your organization administrator immediately.</p>
20
+ </div>
21
+ <div class="footer">&copy; {{year}} {{branding.companyName}}</div>
22
+ </div>
23
+ </body>
24
+ </html>
@@ -0,0 +1,7 @@
1
+ Password changed
2
+
3
+ Hi {{userName}},
4
+
5
+ Your password has been successfully changed. If you did not make this change, please contact your organization administrator immediately.
6
+
7
+ © {{year}} {{branding.companyName}}
@@ -0,0 +1,30 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <style>
7
+ body { font-family: system-ui, sans-serif; margin: 0; padding: 0; background: #f5f5f5; }
8
+ .wrapper { max-width: 560px; margin: 0 auto; padding: 40px 20px; }
9
+ .card { background: white; border-radius: 8px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
10
+ .btn { display: inline-block; background: {{branding.primaryColor}}; color: white; text-decoration: none; padding: 12px 32px; border-radius: 4px; font-size: 16px; font-weight: 500; }
11
+ .footer { text-align: center; padding: 16px; color: #6b7280; font-size: 12px; }
12
+ </style>
13
+ </head>
14
+ <body>
15
+ <div class="wrapper">
16
+ <div class="card">
17
+ {{#if branding.logoUrl}}<img src="{{branding.logoUrl}}" alt="{{branding.companyName}}" style="max-height: 40px; margin-bottom: 16px;">{{/if}}
18
+ <h1 style="font-size: 20px; margin: 0 0 12px 0;">Reset your password</h1>
19
+ <p>Hi {{userName}},</p>
20
+ <p>We received a request to reset your password. Click the button below to set a new one. This link expires in {{expiresMinutes}} minutes.</p>
21
+ <p style="text-align: center; margin: 24px 0;">
22
+ <a href="{{{resetUrl}}}" class="btn">Reset Password</a>
23
+ </p>
24
+ <p style="color: #6b7280; font-size: 13px;">If you didn't request this, you can safely ignore this email. Your password will remain unchanged.</p>
25
+ <p style="color: #6b7280; font-size: 13px;">Or copy this link: {{{resetUrl}}}</p>
26
+ </div>
27
+ <div class="footer">&copy; {{year}} {{branding.companyName}}</div>
28
+ </div>
29
+ </body>
30
+ </html>
@@ -0,0 +1,11 @@
1
+ Reset your password
2
+
3
+ Hi {{userName}},
4
+
5
+ We received a request to reset your password. Click the link below to set a new one. This link expires in {{expiresMinutes}} minutes.
6
+
7
+ {{{resetUrl}}}
8
+
9
+ If you didn't request this, you can safely ignore this email. Your password will remain unchanged.
10
+
11
+ © {{year}} {{branding.companyName}}
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <style>
7
+ body { font-family: system-ui, sans-serif; margin: 0; padding: 0; background: #f5f5f5; }
8
+ .wrapper { max-width: 560px; margin: 0 auto; padding: 40px 20px; }
9
+ .card { background: white; border-radius: 8px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
10
+ .footer { text-align: center; padding: 16px; color: #6b7280; font-size: 12px; }
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <div class="wrapper">
15
+ <div class="card">
16
+ {{#if branding.logoUrl}}<img src="{{branding.logoUrl}}" alt="{{branding.companyName}}" style="max-height: 40px; margin-bottom: 16px;">{{/if}}
17
+ <h1 style="font-size: 20px; margin: 0 0 12px 0;">Welcome to {{orgName}}!</h1>
18
+ <p>Hi {{userName}},</p>
19
+ <p>Your account has been set up successfully. You can now sign in to {{orgName}} using your credentials.</p>
20
+ <p>If you have any questions, contact your organization administrator.</p>
21
+ </div>
22
+ <div class="footer">&copy; {{year}} {{branding.companyName}}</div>
23
+ </div>
24
+ </body>
25
+ </html>
@@ -0,0 +1,9 @@
1
+ Welcome to {{orgName}}!
2
+
3
+ Hi {{userName}},
4
+
5
+ Your account has been set up successfully. You can now sign in to {{orgName}} using your credentials.
6
+
7
+ If you have any questions, contact your organization administrator.
8
+
9
+ © {{year}} {{branding.companyName}}
@@ -0,0 +1,49 @@
1
+ <!DOCTYPE html>
2
+ <html lang="{{locale}}">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ {{#if branding.faviconUrl}}<link rel="icon" href="{{branding.faviconUrl}}">{{/if}}
7
+ <title>{{pageTitle}} — {{branding.companyName}}</title>
8
+ <style>
9
+ :root { --primary: {{branding.primaryColor}}; }
10
+ /* Minimal default styles for login/consent pages */
11
+ * { box-sizing: border-box; }
12
+ body { font-family: system-ui, -apple-system, sans-serif; margin: 0; padding: 40px 20px; background: #f5f5f5; color: #1f2937; line-height: 1.5; }
13
+ .container { max-width: 420px; margin: 0 auto; background: white; padding: 32px; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
14
+ .btn-primary { background: var(--primary); color: white; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; width: 100%; display: inline-block; text-align: center; text-decoration: none; }
15
+ .btn-primary:hover { opacity: 0.9; }
16
+ .btn-secondary { background: white; color: #374151; border: 1px solid #d1d5db; padding: 10px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; width: 100%; display: inline-block; text-align: center; text-decoration: none; }
17
+ .btn-secondary:hover { background: #f9fafb; }
18
+ input[type=email], input[type=password], input[type=text] { width: 100%; padding: 10px; border: 1px solid #d1d5db; border-radius: 4px; font-size: 16px; }
19
+ input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2); }
20
+ label { display: block; margin-bottom: 4px; font-weight: 500; font-size: 14px; }
21
+ .form-group { margin-bottom: 16px; }
22
+ .flash-error { background: #fef2f2; border: 1px solid #fecaca; color: #991b1b; padding: 12px; border-radius: 4px; margin-bottom: 16px; }
23
+ .flash-success { background: #f0fdf4; border: 1px solid #bbf7d0; color: #166534; padding: 12px; border-radius: 4px; margin-bottom: 16px; }
24
+ .flash-info { background: #eff6ff; border: 1px solid #bfdbfe; color: #1e40af; padding: 12px; border-radius: 4px; margin-bottom: 16px; }
25
+ a { color: var(--primary); }
26
+ .divider { text-align: center; margin: 20px 0; position: relative; }
27
+ .divider::before { content: ''; position: absolute; top: 50%; left: 0; right: 0; border-top: 1px solid #e5e7eb; }
28
+ .divider span { background: white; padding: 0 12px; position: relative; color: #6b7280; font-size: 14px; }
29
+ .text-center { text-align: center; }
30
+ .text-muted { color: #6b7280; font-size: 14px; }
31
+ .mt-4 { margin-top: 16px; }
32
+ .mb-4 { margin-bottom: 16px; }
33
+ h1 { font-size: 24px; font-weight: 600; margin: 0 0 8px 0; }
34
+ h2 { font-size: 20px; font-weight: 600; margin: 0 0 8px 0; }
35
+ .scope-list { list-style: none; padding: 0; margin: 12px 0; }
36
+ .scope-list li { padding: 8px 0; border-bottom: 1px solid #f3f4f6; display: flex; align-items: center; gap: 8px; }
37
+ .scope-list li::before { content: '✓'; color: var(--primary); font-weight: bold; }
38
+ </style>
39
+ {{#if branding.customCss}}<style>{{{branding.customCss}}}</style>{{/if}}
40
+ </head>
41
+ <body>
42
+ <div class="container">
43
+ {{> header}}
44
+ {{> flash-messages}}
45
+ {{{body}}}
46
+ {{> footer}}
47
+ </div>
48
+ </body>
49
+ </html>
@@ -0,0 +1,25 @@
1
+ {{!-- Accept invitation: set initial password form --}}
2
+ <h1>{{t "invitation.title"}}</h1>
3
+ <p class="text-muted mb-4">{{t "invitation.description" orgName=orgName}}</p>
4
+
5
+ <form method="POST" action="/{{orgSlug}}/auth/accept-invite/{{token}}">
6
+ <input type="hidden" name="_csrf" value="{{csrfToken}}">
7
+ <input type="hidden" name="token" value="{{token}}">
8
+
9
+ <div class="form-group">
10
+ <label>{{t "invitation.email_label"}}</label>
11
+ <input type="email" value="{{email}}" disabled style="background: #f9fafb;">
12
+ </div>
13
+
14
+ <div class="form-group">
15
+ <label for="password">{{t "invitation.password_label"}}</label>
16
+ <input type="password" id="password" name="password" required autofocus placeholder="{{t "invitation.password_placeholder"}}" minlength="8">
17
+ </div>
18
+
19
+ <div class="form-group">
20
+ <label for="confirmPassword">{{t "invitation.confirm_label"}}</label>
21
+ <input type="password" id="confirmPassword" name="confirmPassword" required placeholder="{{t "invitation.confirm_placeholder"}}" minlength="8">
22
+ </div>
23
+
24
+ <button type="submit" class="btn-primary">{{t "invitation.submit"}}</button>
25
+ </form>
@@ -0,0 +1,27 @@
1
+ {{!-- Consent page: scope approval/deny for third-party applications --}}
2
+ <h1>{{t "consent.title"}}</h1>
3
+ <p class="text-muted mb-4">{{t "consent.description" clientName=interaction.client.clientName}}</p>
4
+
5
+ {{#if scopes.length}}
6
+ <p style="font-weight: 500;">{{t "consent.scopes_heading"}}</p>
7
+ <ul class="scope-list">
8
+ {{#each scopes}}
9
+ <li>{{t (concat "consent.scope_" this)}}</li>
10
+ {{/each}}
11
+ </ul>
12
+ {{/if}}
13
+
14
+ <form method="POST" action="/interaction/{{interaction.uid}}/confirm">
15
+ <input type="hidden" name="_csrf" value="{{csrfToken}}">
16
+ <input type="hidden" name="decision" value="approve">
17
+
18
+ <div class="form-group">
19
+ <button type="submit" class="btn-primary">{{t "consent.approve"}}</button>
20
+ </div>
21
+ </form>
22
+
23
+ <form method="POST" action="/interaction/{{interaction.uid}}/confirm">
24
+ <input type="hidden" name="_csrf" value="{{csrfToken}}">
25
+ <input type="hidden" name="decision" value="deny">
26
+ <button type="submit" class="btn-secondary">{{t "consent.deny"}}</button>
27
+ </form>
@@ -0,0 +1,15 @@
1
+ {{!-- Generic error page --}}
2
+ <div class="text-center">
3
+ <h1>{{t "errors.page_title"}}</h1>
4
+ <p class="text-muted mb-4">{{#if errorMessage}}{{errorMessage}}{{else}}{{t "errors.generic"}}{{/if}}</p>
5
+
6
+ {{#if errorCode}}
7
+ <p class="text-muted" style="font-size: 12px;">{{t "errors.code_label"}}: {{errorCode}}</p>
8
+ {{/if}}
9
+
10
+ {{#if retryUrl}}
11
+ <div class="mt-4">
12
+ <a href="{{retryUrl}}" class="btn-primary" style="display: inline-block; padding: 10px 24px;">{{t "common.try_again"}}</a>
13
+ </div>
14
+ {{/if}}
15
+ </div>
@@ -0,0 +1,21 @@
1
+ {{!-- Forgot password: email input form to request password reset --}}
2
+ <h1>{{t "forgot-password.title"}}</h1>
3
+ <p class="text-muted mb-4">{{t "forgot-password.description"}}</p>
4
+
5
+ <form method="POST" action="/{{orgSlug}}/auth/forgot-password">
6
+ <input type="hidden" name="_csrf" value="{{csrfToken}}">
7
+ {{#if interactionUid}}
8
+ <input type="hidden" name="interaction" value="{{interactionUid}}">
9
+ {{/if}}
10
+
11
+ <div class="form-group">
12
+ <label for="email">{{t "forgot-password.email_label"}}</label>
13
+ <input type="email" id="email" name="email" required autofocus placeholder="{{t "forgot-password.email_placeholder"}}">
14
+ </div>
15
+
16
+ <button type="submit" class="btn-primary">{{t "forgot-password.submit"}}</button>
17
+ </form>
18
+
19
+ <div class="text-center mt-4">
20
+ <a href="/interaction/{{interactionUid}}">{{t "common.back_to_login"}}</a>
21
+ </div>
@@ -0,0 +1,6 @@
1
+ {{!-- Invitation expired or invalid token --}}
2
+ <div class="text-center">
3
+ <h1>{{t "invitation.expired_title"}}</h1>
4
+ <p class="text-muted mb-4">{{t "invitation.expired_message"}}</p>
5
+ <p class="text-muted">{{t "invitation.contact_admin"}}</p>
6
+ </div>
@@ -0,0 +1,9 @@
1
+ {{!-- Invitation accepted: account setup complete --}}
2
+ <div class="text-center">
3
+ <h1>{{t "invitation.success_title"}}</h1>
4
+ <p class="text-muted mb-4">{{t "invitation.success_message"}}</p>
5
+
6
+ {{#if loginUrl}}
7
+ <a href="{{loginUrl}}" class="btn-primary" style="display: inline-block; padding: 10px 24px;">{{t "invitation.go_to_login"}}</a>
8
+ {{/if}}
9
+ </div>
@@ -0,0 +1,108 @@
1
+ {{!--
2
+ Login page — renders ONLY the login methods enabled for the current client.
3
+
4
+ Context contract (set in src/routes/interactions.ts#showLogin):
5
+ showPassword : boolean — render the email+password form
6
+ showMagicLink : boolean — render the magic-link button
7
+ showDivider : boolean — render the "or" divider (true iff BOTH above)
8
+ emailHint : string? — login_hint from the OIDC authorize request
9
+ loginMethods : LoginMethod[] — effective methods (client override or org default)
10
+
11
+ Rendering matrix (client metadata → UI):
12
+ ['password','magic_link'] → both forms, divider, magic-link JS copies email
13
+ ['password'] → password form only, no divider, no JS
14
+ ['magic_link'] → standalone magic-link form with its OWN email input, no JS
15
+ [] → resolver forbids this — we never reach here
16
+ --}}
17
+ <h1>{{t "login.title"}}</h1>
18
+ <p class="text-muted mb-4">{{t "login.subtitle" clientName=interaction.client.clientName}}</p>
19
+
20
+ {{#if showPassword}}
21
+ {{!-- Password login — email+password+submit. When magic-link is also
22
+ enabled, the shared #email input is also read by the magic-link form
23
+ via the script at the bottom of the page. --}}
24
+ <form method="POST" action="/interaction/{{interaction.uid}}/login">
25
+ <input type="hidden" name="_csrf" value="{{csrfToken}}">
26
+
27
+ <div class="form-group">
28
+ <label for="email">{{t "login.email_label"}}</label>
29
+ <input type="email" id="email" name="email" required autofocus
30
+ placeholder="{{t "login.email_placeholder"}}"
31
+ value="{{#if emailHint}}{{emailHint}}{{else}}{{email}}{{/if}}">
32
+ </div>
33
+
34
+ <div class="form-group">
35
+ <label for="password">{{t "login.password_label"}}</label>
36
+ <input type="password" id="password" name="password" required
37
+ placeholder="{{t "login.password_placeholder"}}">
38
+ </div>
39
+
40
+ {{!-- Forgot-password link only makes sense when password auth is enabled.
41
+ Wrap it in showPassword so magic-link-only clients don't advertise a
42
+ password-recovery flow that enforcePasswordMethod() will block anyway. --}}
43
+ <div class="form-group">
44
+ <a href="/{{orgSlug}}/auth/forgot-password?interaction={{interaction.uid}}"
45
+ class="text-muted" style="font-size: 13px;">{{t "login.forgot_password"}}</a>
46
+ </div>
47
+
48
+ <button type="submit" class="btn-primary">{{t "login.submit"}}</button>
49
+ </form>
50
+ {{/if}}
51
+
52
+ {{#if showDivider}}
53
+ <div class="divider"><span>{{t "login.or_divider"}}</span></div>
54
+ {{/if}}
55
+
56
+ {{#if showMagicLink}}
57
+ {{#if showPassword}}
58
+ {{!-- Dual-method mode: the magic-link form has a hidden email field that
59
+ the script below copies from the shared #email input. --}}
60
+ <form method="POST" action="/interaction/{{interaction.uid}}/magic-link">
61
+ <input type="hidden" name="_csrf" value="{{csrfToken}}">
62
+ <input type="hidden" name="email" value="">
63
+ <button type="submit" class="btn-secondary" id="magic-link-btn">
64
+ {{t "login.magic_link_button"}}
65
+ </button>
66
+ </form>
67
+ {{else}}
68
+ {{!-- Magic-link-only mode: there's no password form on the page, so we
69
+ render a standalone email input as a required field. No JS needed. --}}
70
+ <form method="POST" action="/interaction/{{interaction.uid}}/magic-link">
71
+ <input type="hidden" name="_csrf" value="{{csrfToken}}">
72
+
73
+ <div class="form-group">
74
+ <label for="email">{{t "login.email_label"}}</label>
75
+ <input type="email" id="email" name="email" required autofocus
76
+ placeholder="{{t "login.email_placeholder"}}"
77
+ value="{{#if emailHint}}{{emailHint}}{{else}}{{email}}{{/if}}">
78
+ </div>
79
+
80
+ <button type="submit" class="btn-primary">{{t "login.magic_link_button"}}</button>
81
+ </form>
82
+ {{/if}}
83
+ {{/if}}
84
+
85
+ {{#unless showPassword}}{{#unless showMagicLink}}
86
+ {{!-- No-methods fallback. The resolver guarantees we never reach here
87
+ (resolveLoginMethods returns at least one method), but rendering a
88
+ clear message is safer than a blank page if the contract is ever
89
+ accidentally violated (e.g. a misconfigured template context). --}}
90
+ <div class="alert alert-error" role="alert">
91
+ {{t "errors.no_login_methods_configured"}}
92
+ </div>
93
+ {{/unless}}{{/unless}}
94
+
95
+ {{#if showDivider}}
96
+ {{!-- This script only belongs to the dual-method layout, where the
97
+ magic-link <form> has a hidden email field fed from the shared
98
+ password-form #email input. Single-method layouts don't need it:
99
+ - password-only: no magic-link form to submit
100
+ - magic-link-only: the form has its own real email input --}}
101
+ <script>
102
+ document.getElementById('magic-link-btn').closest('form').addEventListener('submit', function(e) {
103
+ var emailInput = document.getElementById('email');
104
+ this.querySelector('input[name="email"]').value = emailInput.value;
105
+ if (!emailInput.value) { e.preventDefault(); emailInput.focus(); }
106
+ });
107
+ </script>
108
+ {{/if}}
@@ -0,0 +1,5 @@
1
+ {{!-- Post-logout success page --}}
2
+ <div class="text-center">
3
+ <h1>{{t "logout.success_title"}}</h1>
4
+ <p class="text-muted mb-4">{{t "logout.success_message"}}</p>
5
+ </div>
@@ -0,0 +1,24 @@
1
+ {{!-- Logout confirmation page --}}
2
+ {{!-- Shows a "Sign Out" button (submits the provider's form) and a
3
+ "Return to Application" link (if a post_logout_redirect_uri is available).
4
+ The logoutForm variable contains the provider's pre-built form with
5
+ action URL, xsrf token, and a styled submit button. --}}
6
+ <div class="text-center">
7
+ <h1>{{t "logout.title"}}</h1>
8
+
9
+ {{#if clientName}}
10
+ <p class="text-muted mb-4">{{t "logout.message_client"}}</p>
11
+ {{else}}
12
+ <p class="text-muted mb-4">{{t "logout.message"}}</p>
13
+ {{/if}}
14
+
15
+ {{!-- Sign Out button — submits the provider's end_session confirmation form --}}
16
+ {{{logoutForm}}}
17
+
18
+ {{!-- Return to Application link — only shown when a redirect URI is available --}}
19
+ {{#if returnUrl}}
20
+ <div class="mt-3">
21
+ <a href="{{returnUrl}}" class="text-muted">{{t "logout.cancel"}}</a>
22
+ </div>
23
+ {{/if}}
24
+ </div>
@@ -0,0 +1,10 @@
1
+ {{!-- Magic link sent: "check your email" confirmation --}}
2
+ <div class="text-center">
3
+ <h1>{{t "magic-link.sent_title"}}</h1>
4
+ <p class="text-muted mb-4">{{t "magic-link.check_email" email=email}}</p>
5
+ <p class="text-muted">{{t "magic-link.expires_note"}}</p>
6
+
7
+ <div class="mt-4">
8
+ <a href="{{loginUrl}}">{{t "common.back_to_login"}}</a>
9
+ </div>
10
+ </div>
@@ -0,0 +1,17 @@
1
+ {{!-- Magic link verified: shown when link is opened in a different browser --}}
2
+ {{!--
3
+ Displayed when a magic link is opened in a different browser than the one
4
+ that started the OIDC authorization flow. The magic link IS verified and
5
+ the user's email is confirmed, but the OIDC flow completes in the original
6
+ browser where the interaction cookies reside.
7
+
8
+ Security: This page is ONLY rendered when a valid _ml_session cookie
9
+ was present and consumed. The session is single-use (Redis key deleted),
10
+ so this page cannot be shown by URL crafting or replay.
11
+ --}}
12
+ <div class="text-center">
13
+ <h1>{{t "magic-link.success_title"}}</h1>
14
+ <p class="text-muted mb-4">{{t "magic-link.success_message"}}</p>
15
+ <p class="text-muted">{{t "magic-link.success_hint"}}</p>
16
+ <p class="text-muted mt-2">{{t "magic-link.success_close_tab"}}</p>
17
+ </div>
@@ -0,0 +1,20 @@
1
+ {{!-- Reset password: new password form (arrived via email link) --}}
2
+ <h1>{{t "reset-password.title"}}</h1>
3
+ <p class="text-muted mb-4">{{t "reset-password.description"}}</p>
4
+
5
+ <form method="POST" action="/{{orgSlug}}/auth/reset-password/{{token}}">
6
+ <input type="hidden" name="_csrf" value="{{csrfToken}}">
7
+ <input type="hidden" name="token" value="{{token}}">
8
+
9
+ <div class="form-group">
10
+ <label for="password">{{t "reset-password.password_label"}}</label>
11
+ <input type="password" id="password" name="password" required autofocus placeholder="{{t "reset-password.password_placeholder"}}" minlength="8">
12
+ </div>
13
+
14
+ <div class="form-group">
15
+ <label for="confirmPassword">{{t "reset-password.confirm_label"}}</label>
16
+ <input type="password" id="confirmPassword" name="confirmPassword" required placeholder="{{t "reset-password.confirm_placeholder"}}" minlength="8">
17
+ </div>
18
+
19
+ <button type="submit" class="btn-primary">{{t "reset-password.submit"}}</button>
20
+ </form>
@@ -0,0 +1,9 @@
1
+ {{!-- Password reset success confirmation --}}
2
+ <div class="text-center">
3
+ <h1>{{t "reset-password.success_title"}}</h1>
4
+ <p class="text-muted mb-4">{{t "reset-password.success_message"}}</p>
5
+
6
+ {{#if loginUrl}}
7
+ <a href="{{loginUrl}}" class="btn-primary" style="display: inline-block; padding: 10px 24px;">{{t "reset-password.back_to_login"}}</a>
8
+ {{/if}}
9
+ </div>
@@ -0,0 +1,65 @@
1
+ {{!-- Two-factor setup page: TOTP QR code enrollment + recovery codes --}}
2
+ <h1>{{t "two-factor.setup_title"}}</h1>
3
+ <p class="text-muted mb-4">{{t "two-factor.setup_subtitle"}}</p>
4
+
5
+ {{!-- flash-messages partial is already rendered by the main layout --}}
6
+
7
+ <div style="margin-bottom: 24px;">
8
+ <h2 style="font-size: 16px; margin-bottom: 8px;">{{t "two-factor.setup_step1"}}</h2>
9
+ <p style="font-size: 13px; color: #6b7280; margin-bottom: 16px;">{{t "two-factor.setup_scan_instructions"}}</p>
10
+
11
+ {{#if qrCodeDataUri}}
12
+ <div style="text-align: center; margin-bottom: 16px;">
13
+ <img src="{{qrCodeDataUri}}" alt="{{t "two-factor.qr_code_alt"}}" style="width: 200px; height: 200px; border: 1px solid #e5e7eb; border-radius: 8px; padding: 8px;">
14
+ </div>
15
+ {{/if}}
16
+
17
+ {{#if totpSecret}}
18
+ <div style="text-align: center; margin-bottom: 16px;">
19
+ <p style="font-size: 12px; color: #6b7280;">{{t "two-factor.manual_entry_label"}}</p>
20
+ <code style="font-size: 14px; background: #f3f4f6; padding: 8px 16px; border-radius: 4px; letter-spacing: 2px; user-select: all;">{{totpSecret}}</code>
21
+ </div>
22
+ {{/if}}
23
+ </div>
24
+
25
+ <div style="margin-bottom: 24px;">
26
+ <h2 style="font-size: 16px; margin-bottom: 8px;">{{t "two-factor.setup_step2"}}</h2>
27
+ <p style="font-size: 13px; color: #6b7280; margin-bottom: 16px;">{{t "two-factor.setup_enter_code_instructions"}}</p>
28
+
29
+ <form method="POST" action="/interaction/{{interaction.uid}}/two-factor/setup">
30
+ <input type="hidden" name="_csrf" value="{{csrfToken}}">
31
+ <input type="hidden" name="setupMethod" value="totp">
32
+
33
+ <div class="form-group">
34
+ <label for="code">{{t "two-factor.totp_code_label"}}</label>
35
+ <input type="text" id="code" name="code" required autofocus
36
+ placeholder="000000" maxlength="6"
37
+ autocomplete="one-time-code" inputmode="numeric"
38
+ pattern="[0-9]{6}"
39
+ style="font-size: 24px; letter-spacing: 4px; text-align: center; max-width: 200px;">
40
+ </div>
41
+
42
+ <button type="submit" class="btn-primary">{{t "two-factor.confirm_setup_button"}}</button>
43
+ </form>
44
+ </div>
45
+
46
+ {{#if recoveryCodes}}
47
+ <div style="margin-top: 32px; padding: 16px; background: #fffbeb; border: 1px solid #fbbf24; border-radius: 8px;">
48
+ <h2 style="font-size: 16px; margin-bottom: 8px; color: #92400e;">{{t "two-factor.recovery_codes_title"}}</h2>
49
+ <p style="font-size: 13px; color: #92400e; margin-bottom: 12px;">{{t "two-factor.recovery_codes_warning"}}</p>
50
+
51
+ <div style="background: white; padding: 12px; border-radius: 4px; font-family: monospace; font-size: 14px; line-height: 1.8; columns: 2; column-gap: 24px;">
52
+ {{#each recoveryCodes}}
53
+ <div>{{this}}</div>
54
+ {{/each}}
55
+ </div>
56
+ </div>
57
+ {{/if}}
58
+
59
+ <div class="divider"><span>{{t "two-factor.or_divider"}}</span></div>
60
+
61
+ <form method="POST" action="/interaction/{{interaction.uid}}/two-factor/setup">
62
+ <input type="hidden" name="_csrf" value="{{csrfToken}}">
63
+ <input type="hidden" name="setupMethod" value="email">
64
+ <button type="submit" class="btn-secondary">{{t "two-factor.use_email_instead"}}</button>
65
+ </form>