@contember/engine-tenant-api 2.2.0-alpha.2 → 2.2.0-alpha.5

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 (1181) hide show
  1. package/CLAUDE.md +35 -2
  2. package/dist/development/index.cjs +30 -0
  3. package/dist/development/index.cjs.map +1 -1
  4. package/dist/development/index.js +31 -1
  5. package/dist/development/index.js.map +1 -1
  6. package/dist/development/src/TenantContainer.cjs +15 -3
  7. package/dist/development/src/TenantContainer.cjs.map +1 -1
  8. package/dist/development/src/TenantContainer.js +15 -3
  9. package/dist/development/src/TenantContainer.js.map +1 -1
  10. package/dist/development/src/bridges/system/IdentityFetcher.cjs +2 -1
  11. package/dist/development/src/bridges/system/IdentityFetcher.cjs.map +1 -1
  12. package/dist/development/src/bridges/system/IdentityFetcher.js +2 -1
  13. package/dist/development/src/bridges/system/IdentityFetcher.js.map +1 -1
  14. package/dist/development/src/migrations/2026-06-18-120000-idp-claim-mapping.cjs +10 -0
  15. package/dist/development/src/migrations/2026-06-18-120000-idp-claim-mapping.cjs.map +1 -0
  16. package/dist/development/src/migrations/2026-06-18-120000-idp-claim-mapping.js +11 -0
  17. package/dist/development/src/migrations/2026-06-18-120000-idp-claim-mapping.js.map +1 -0
  18. package/dist/development/src/migrations/2026-08-03-120000-person-enable-auth-log.cjs +9 -0
  19. package/dist/development/src/migrations/2026-08-03-120000-person-enable-auth-log.cjs.map +1 -0
  20. package/dist/development/src/migrations/2026-08-03-120000-person-enable-auth-log.js +10 -0
  21. package/dist/development/src/migrations/2026-08-03-120000-person-enable-auth-log.js.map +1 -0
  22. package/dist/development/src/migrations/2026-08-04-120000-config-panel.cjs +11 -0
  23. package/dist/development/src/migrations/2026-08-04-120000-config-panel.cjs.map +1 -0
  24. package/dist/development/src/migrations/2026-08-04-120000-config-panel.js +12 -0
  25. package/dist/development/src/migrations/2026-08-04-120000-config-panel.js.map +1 -0
  26. package/dist/development/src/migrations/runner.cjs +9 -2
  27. package/dist/development/src/migrations/runner.cjs.map +1 -1
  28. package/dist/development/src/migrations/runner.js +9 -2
  29. package/dist/development/src/migrations/runner.js.map +1 -1
  30. package/dist/development/src/migrations/snapshot.cjs +6 -1
  31. package/dist/development/src/migrations/snapshot.cjs.map +1 -1
  32. package/dist/development/src/migrations/snapshot.js +6 -1
  33. package/dist/development/src/migrations/snapshot.js.map +1 -1
  34. package/dist/development/src/model/commands/configuration/UpdateConfigurationCommand.cjs +5 -3
  35. package/dist/development/src/model/commands/configuration/UpdateConfigurationCommand.cjs.map +1 -1
  36. package/dist/development/src/model/commands/configuration/UpdateConfigurationCommand.js +5 -3
  37. package/dist/development/src/model/commands/configuration/UpdateConfigurationCommand.js.map +1 -1
  38. package/dist/development/src/model/commands/membership/{RemoveProjectMembershipsCommand.cjs → RemoveProjectMembershipCommand.cjs} +1 -1
  39. package/dist/development/src/model/commands/membership/RemoveProjectMembershipCommand.cjs.map +1 -0
  40. package/dist/development/src/model/commands/membership/{RemoveProjectMembershipsCommand.js → RemoveProjectMembershipCommand.js} +1 -1
  41. package/dist/development/src/model/commands/membership/RemoveProjectMembershipCommand.js.map +1 -0
  42. package/dist/development/src/model/commands/membership/UpdateProjectMemberCommand.cjs +2 -2
  43. package/dist/development/src/model/commands/membership/UpdateProjectMemberCommand.cjs.map +1 -1
  44. package/dist/development/src/model/commands/membership/UpdateProjectMemberCommand.js +1 -1
  45. package/dist/development/src/model/commands/membership/UpdateProjectMemberCommand.js.map +1 -1
  46. package/dist/development/src/model/commands/person/EnablePersonCommand.cjs +17 -0
  47. package/dist/development/src/model/commands/person/EnablePersonCommand.cjs.map +1 -0
  48. package/dist/development/src/model/commands/person/EnablePersonCommand.js +17 -0
  49. package/dist/development/src/model/commands/person/EnablePersonCommand.js.map +1 -0
  50. package/dist/development/src/model/queries/configuration/ConfigurationQuery.cjs +4 -0
  51. package/dist/development/src/model/queries/configuration/ConfigurationQuery.cjs.map +1 -1
  52. package/dist/development/src/model/queries/configuration/ConfigurationQuery.js +4 -0
  53. package/dist/development/src/model/queries/configuration/ConfigurationQuery.js.map +1 -1
  54. package/dist/development/src/model/queries/membership/ProjectMembersQuery.cjs +1 -1
  55. package/dist/development/src/model/queries/membership/ProjectMembersQuery.cjs.map +1 -1
  56. package/dist/development/src/model/queries/membership/ProjectMembersQuery.js +1 -1
  57. package/dist/development/src/model/queries/membership/ProjectMembersQuery.js.map +1 -1
  58. package/dist/development/src/model/queries/person/PersonQueryBuilderFactory.cjs +1 -1
  59. package/dist/development/src/model/queries/person/PersonQueryBuilderFactory.cjs.map +1 -1
  60. package/dist/development/src/model/queries/person/PersonQueryBuilderFactory.js +1 -1
  61. package/dist/development/src/model/queries/person/PersonQueryBuilderFactory.js.map +1 -1
  62. package/dist/development/src/model/service/AuthLogService.cjs +8 -2
  63. package/dist/development/src/model/service/AuthLogService.cjs.map +1 -1
  64. package/dist/development/src/model/service/AuthLogService.js +8 -2
  65. package/dist/development/src/model/service/AuthLogService.js.map +1 -1
  66. package/dist/development/src/model/service/IDPSignInManager.cjs +29 -2
  67. package/dist/development/src/model/service/IDPSignInManager.cjs.map +1 -1
  68. package/dist/development/src/model/service/IDPSignInManager.js +29 -2
  69. package/dist/development/src/model/service/IDPSignInManager.js.map +1 -1
  70. package/dist/development/src/model/service/PanelAccessResolver.cjs +31 -0
  71. package/dist/development/src/model/service/PanelAccessResolver.cjs.map +1 -0
  72. package/dist/development/src/model/service/PanelAccessResolver.js +31 -0
  73. package/dist/development/src/model/service/PanelAccessResolver.js.map +1 -0
  74. package/dist/development/src/model/service/PersonAccessManager.cjs +10 -2
  75. package/dist/development/src/model/service/PersonAccessManager.cjs.map +1 -1
  76. package/dist/development/src/model/service/PersonAccessManager.js +10 -2
  77. package/dist/development/src/model/service/PersonAccessManager.js.map +1 -1
  78. package/dist/development/src/model/service/apiKey/ApiKeyManager.cjs +4 -3
  79. package/dist/development/src/model/service/apiKey/ApiKeyManager.cjs.map +1 -1
  80. package/dist/development/src/model/service/apiKey/ApiKeyManager.js +4 -3
  81. package/dist/development/src/model/service/apiKey/ApiKeyManager.js.map +1 -1
  82. package/dist/development/src/model/service/apiKey/UnpersistedApiKeyManager.cjs +7 -0
  83. package/dist/development/src/model/service/apiKey/UnpersistedApiKeyManager.cjs.map +1 -1
  84. package/dist/development/src/model/service/apiKey/UnpersistedApiKeyManager.js +8 -1
  85. package/dist/development/src/model/service/apiKey/UnpersistedApiKeyManager.js.map +1 -1
  86. package/dist/development/src/model/service/idp/ClaimMapping.cjs +187 -0
  87. package/dist/development/src/model/service/idp/ClaimMapping.cjs.map +1 -0
  88. package/dist/development/src/model/service/idp/ClaimMapping.js +170 -0
  89. package/dist/development/src/model/service/idp/ClaimMapping.js.map +1 -0
  90. package/dist/development/src/model/service/idp/ClaimMappingEvaluator.cjs +155 -0
  91. package/dist/development/src/model/service/idp/ClaimMappingEvaluator.cjs.map +1 -0
  92. package/dist/development/src/model/service/idp/ClaimMappingEvaluator.js +155 -0
  93. package/dist/development/src/model/service/idp/ClaimMappingEvaluator.js.map +1 -0
  94. package/dist/development/src/model/service/idp/ClaimMappingValidation.cjs +83 -0
  95. package/dist/development/src/model/service/idp/ClaimMappingValidation.cjs.map +1 -0
  96. package/dist/development/src/model/service/idp/ClaimMappingValidation.js +83 -0
  97. package/dist/development/src/model/service/idp/ClaimMappingValidation.js.map +1 -0
  98. package/dist/development/src/model/service/idp/IDPClaimSyncService.cjs +260 -0
  99. package/dist/development/src/model/service/idp/IDPClaimSyncService.cjs.map +1 -0
  100. package/dist/development/src/model/service/idp/IDPClaimSyncService.js +260 -0
  101. package/dist/development/src/model/service/idp/IDPClaimSyncService.js.map +1 -0
  102. package/dist/development/src/model/service/idp/IDPManager.cjs +96 -20
  103. package/dist/development/src/model/service/idp/IDPManager.cjs.map +1 -1
  104. package/dist/development/src/model/service/idp/IDPManager.js +96 -20
  105. package/dist/development/src/model/service/idp/IDPManager.js.map +1 -1
  106. package/dist/development/src/model/service/idp/IdpSessionRevalidator.cjs +55 -1
  107. package/dist/development/src/model/service/idp/IdpSessionRevalidator.cjs.map +1 -1
  108. package/dist/development/src/model/service/idp/IdpSessionRevalidator.js +55 -1
  109. package/dist/development/src/model/service/idp/IdpSessionRevalidator.js.map +1 -1
  110. package/dist/development/src/model/service/idp/providers/OIDCHelpers.cjs +69 -33
  111. package/dist/development/src/model/service/idp/providers/OIDCHelpers.cjs.map +1 -1
  112. package/dist/development/src/model/service/idp/providers/OIDCHelpers.js +69 -33
  113. package/dist/development/src/model/service/idp/providers/OIDCHelpers.js.map +1 -1
  114. package/dist/development/src/model/service/idp/providers/OIDCProvider.cjs +4 -1
  115. package/dist/development/src/model/service/idp/providers/OIDCProvider.cjs.map +1 -1
  116. package/dist/development/src/model/service/idp/providers/OIDCProvider.js +4 -1
  117. package/dist/development/src/model/service/idp/providers/OIDCProvider.js.map +1 -1
  118. package/dist/development/src/model/utils/DatabaseContext.cjs +7 -2
  119. package/dist/development/src/model/utils/DatabaseContext.cjs.map +1 -1
  120. package/dist/development/src/model/utils/DatabaseContext.js +8 -3
  121. package/dist/development/src/model/utils/DatabaseContext.js.map +1 -1
  122. package/dist/development/src/resolvers/ResolverFactory.cjs +6 -2
  123. package/dist/development/src/resolvers/ResolverFactory.cjs.map +1 -1
  124. package/dist/development/src/resolvers/ResolverFactory.js +6 -2
  125. package/dist/development/src/resolvers/ResolverFactory.js.map +1 -1
  126. package/dist/development/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.cjs +2 -1
  127. package/dist/development/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.cjs.map +1 -1
  128. package/dist/development/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.js +2 -1
  129. package/dist/development/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.js.map +1 -1
  130. package/dist/development/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.cjs +2 -1
  131. package/dist/development/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.cjs.map +1 -1
  132. package/dist/development/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.js +2 -1
  133. package/dist/development/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.js.map +1 -1
  134. package/dist/development/src/resolvers/mutation/configuration/AuthPolicyMutationResolver.cjs +2 -1
  135. package/dist/development/src/resolvers/mutation/configuration/AuthPolicyMutationResolver.cjs.map +1 -1
  136. package/dist/development/src/resolvers/mutation/configuration/AuthPolicyMutationResolver.js +2 -1
  137. package/dist/development/src/resolvers/mutation/configuration/AuthPolicyMutationResolver.js.map +1 -1
  138. package/dist/development/src/resolvers/mutation/configuration/ConfigurationMutationResolver.cjs +2 -1
  139. package/dist/development/src/resolvers/mutation/configuration/ConfigurationMutationResolver.cjs.map +1 -1
  140. package/dist/development/src/resolvers/mutation/configuration/ConfigurationMutationResolver.js +2 -1
  141. package/dist/development/src/resolvers/mutation/configuration/ConfigurationMutationResolver.js.map +1 -1
  142. package/dist/development/src/resolvers/mutation/identity/GlobalRolesMutationResolver.cjs +2 -1
  143. package/dist/development/src/resolvers/mutation/identity/GlobalRolesMutationResolver.cjs.map +1 -1
  144. package/dist/development/src/resolvers/mutation/identity/GlobalRolesMutationResolver.js +2 -1
  145. package/dist/development/src/resolvers/mutation/identity/GlobalRolesMutationResolver.js.map +1 -1
  146. package/dist/development/src/resolvers/mutation/idp/AddIDPMutationResolver.cjs +2 -1
  147. package/dist/development/src/resolvers/mutation/idp/AddIDPMutationResolver.cjs.map +1 -1
  148. package/dist/development/src/resolvers/mutation/idp/AddIDPMutationResolver.js +2 -1
  149. package/dist/development/src/resolvers/mutation/idp/AddIDPMutationResolver.js.map +1 -1
  150. package/dist/development/src/resolvers/mutation/idp/DisableIDPMutationResolver.cjs +2 -1
  151. package/dist/development/src/resolvers/mutation/idp/DisableIDPMutationResolver.cjs.map +1 -1
  152. package/dist/development/src/resolvers/mutation/idp/DisableIDPMutationResolver.js +2 -1
  153. package/dist/development/src/resolvers/mutation/idp/DisableIDPMutationResolver.js.map +1 -1
  154. package/dist/development/src/resolvers/mutation/idp/DisconnectMyIdentityProviderMutationResolver.cjs +2 -1
  155. package/dist/development/src/resolvers/mutation/idp/DisconnectMyIdentityProviderMutationResolver.cjs.map +1 -1
  156. package/dist/development/src/resolvers/mutation/idp/DisconnectMyIdentityProviderMutationResolver.js +2 -1
  157. package/dist/development/src/resolvers/mutation/idp/DisconnectMyIdentityProviderMutationResolver.js.map +1 -1
  158. package/dist/development/src/resolvers/mutation/idp/EnableIDPMutationResolver.cjs +2 -1
  159. package/dist/development/src/resolvers/mutation/idp/EnableIDPMutationResolver.cjs.map +1 -1
  160. package/dist/development/src/resolvers/mutation/idp/EnableIDPMutationResolver.js +2 -1
  161. package/dist/development/src/resolvers/mutation/idp/EnableIDPMutationResolver.js.map +1 -1
  162. package/dist/development/src/resolvers/mutation/idp/UpdateIDPMutationResolver.cjs +2 -1
  163. package/dist/development/src/resolvers/mutation/idp/UpdateIDPMutationResolver.cjs.map +1 -1
  164. package/dist/development/src/resolvers/mutation/idp/UpdateIDPMutationResolver.js +2 -1
  165. package/dist/development/src/resolvers/mutation/idp/UpdateIDPMutationResolver.js.map +1 -1
  166. package/dist/development/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.cjs +2 -1
  167. package/dist/development/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.cjs.map +1 -1
  168. package/dist/development/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.js +2 -1
  169. package/dist/development/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.js.map +1 -1
  170. package/dist/development/src/resolvers/mutation/person/ChangePasswordMutationResolver.cjs +2 -1
  171. package/dist/development/src/resolvers/mutation/person/ChangePasswordMutationResolver.cjs.map +1 -1
  172. package/dist/development/src/resolvers/mutation/person/ChangePasswordMutationResolver.js +2 -1
  173. package/dist/development/src/resolvers/mutation/person/ChangePasswordMutationResolver.js.map +1 -1
  174. package/dist/development/src/resolvers/mutation/person/ChangeProfileMutationResolver.cjs +2 -1
  175. package/dist/development/src/resolvers/mutation/person/ChangeProfileMutationResolver.cjs.map +1 -1
  176. package/dist/development/src/resolvers/mutation/person/ChangeProfileMutationResolver.js +2 -1
  177. package/dist/development/src/resolvers/mutation/person/ChangeProfileMutationResolver.js.map +1 -1
  178. package/dist/development/src/resolvers/mutation/person/DisablePersonMutationResolver.cjs +4 -3
  179. package/dist/development/src/resolvers/mutation/person/DisablePersonMutationResolver.cjs.map +1 -1
  180. package/dist/development/src/resolvers/mutation/person/DisablePersonMutationResolver.js +4 -3
  181. package/dist/development/src/resolvers/mutation/person/DisablePersonMutationResolver.js.map +1 -1
  182. package/dist/development/src/resolvers/mutation/person/EmailOtpMutationResolver.cjs +2 -1
  183. package/dist/development/src/resolvers/mutation/person/EmailOtpMutationResolver.cjs.map +1 -1
  184. package/dist/development/src/resolvers/mutation/person/EmailOtpMutationResolver.js +2 -1
  185. package/dist/development/src/resolvers/mutation/person/EmailOtpMutationResolver.js.map +1 -1
  186. package/dist/development/src/resolvers/mutation/person/EmailVerificationMutationResolver.cjs +2 -1
  187. package/dist/development/src/resolvers/mutation/person/EmailVerificationMutationResolver.cjs.map +1 -1
  188. package/dist/development/src/resolvers/mutation/person/EmailVerificationMutationResolver.js +2 -1
  189. package/dist/development/src/resolvers/mutation/person/EmailVerificationMutationResolver.js.map +1 -1
  190. package/dist/development/src/resolvers/mutation/person/EnablePersonMutationResolver.cjs +60 -0
  191. package/dist/development/src/resolvers/mutation/person/EnablePersonMutationResolver.cjs.map +1 -0
  192. package/dist/development/src/resolvers/mutation/person/EnablePersonMutationResolver.js +60 -0
  193. package/dist/development/src/resolvers/mutation/person/EnablePersonMutationResolver.js.map +1 -0
  194. package/dist/development/src/resolvers/mutation/person/ForceSignOutMutationResolver.cjs +2 -1
  195. package/dist/development/src/resolvers/mutation/person/ForceSignOutMutationResolver.cjs.map +1 -1
  196. package/dist/development/src/resolvers/mutation/person/ForceSignOutMutationResolver.js +2 -1
  197. package/dist/development/src/resolvers/mutation/person/ForceSignOutMutationResolver.js.map +1 -1
  198. package/dist/development/src/resolvers/mutation/person/IDPMutationResolver.cjs +27 -1
  199. package/dist/development/src/resolvers/mutation/person/IDPMutationResolver.cjs.map +1 -1
  200. package/dist/development/src/resolvers/mutation/person/IDPMutationResolver.js +27 -1
  201. package/dist/development/src/resolvers/mutation/person/IDPMutationResolver.js.map +1 -1
  202. package/dist/development/src/resolvers/mutation/person/InviteMutationResolver.cjs +2 -1
  203. package/dist/development/src/resolvers/mutation/person/InviteMutationResolver.cjs.map +1 -1
  204. package/dist/development/src/resolvers/mutation/person/InviteMutationResolver.js +2 -1
  205. package/dist/development/src/resolvers/mutation/person/InviteMutationResolver.js.map +1 -1
  206. package/dist/development/src/resolvers/mutation/person/OtpMutationResolver.cjs +2 -1
  207. package/dist/development/src/resolvers/mutation/person/OtpMutationResolver.cjs.map +1 -1
  208. package/dist/development/src/resolvers/mutation/person/OtpMutationResolver.js +2 -1
  209. package/dist/development/src/resolvers/mutation/person/OtpMutationResolver.js.map +1 -1
  210. package/dist/development/src/resolvers/mutation/person/PasswordlessMutationResolver.cjs +2 -1
  211. package/dist/development/src/resolvers/mutation/person/PasswordlessMutationResolver.cjs.map +1 -1
  212. package/dist/development/src/resolvers/mutation/person/PasswordlessMutationResolver.js +2 -1
  213. package/dist/development/src/resolvers/mutation/person/PasswordlessMutationResolver.js.map +1 -1
  214. package/dist/development/src/resolvers/mutation/person/RegenerateBackupCodesMutationResolver.cjs +2 -1
  215. package/dist/development/src/resolvers/mutation/person/RegenerateBackupCodesMutationResolver.cjs.map +1 -1
  216. package/dist/development/src/resolvers/mutation/person/RegenerateBackupCodesMutationResolver.js +2 -1
  217. package/dist/development/src/resolvers/mutation/person/RegenerateBackupCodesMutationResolver.js.map +1 -1
  218. package/dist/development/src/resolvers/mutation/person/ResetPasswordMutationResolver.cjs +2 -1
  219. package/dist/development/src/resolvers/mutation/person/ResetPasswordMutationResolver.cjs.map +1 -1
  220. package/dist/development/src/resolvers/mutation/person/ResetPasswordMutationResolver.js +2 -1
  221. package/dist/development/src/resolvers/mutation/person/ResetPasswordMutationResolver.js.map +1 -1
  222. package/dist/development/src/resolvers/mutation/person/ResetPersonMfaMutationResolver.cjs +2 -1
  223. package/dist/development/src/resolvers/mutation/person/ResetPersonMfaMutationResolver.cjs.map +1 -1
  224. package/dist/development/src/resolvers/mutation/person/ResetPersonMfaMutationResolver.js +2 -1
  225. package/dist/development/src/resolvers/mutation/person/ResetPersonMfaMutationResolver.js.map +1 -1
  226. package/dist/development/src/resolvers/mutation/person/RevokeSessionMutationResolver.cjs +2 -1
  227. package/dist/development/src/resolvers/mutation/person/RevokeSessionMutationResolver.cjs.map +1 -1
  228. package/dist/development/src/resolvers/mutation/person/RevokeSessionMutationResolver.js +2 -1
  229. package/dist/development/src/resolvers/mutation/person/RevokeSessionMutationResolver.js.map +1 -1
  230. package/dist/development/src/resolvers/mutation/person/SignInMutationResolver.cjs +2 -1
  231. package/dist/development/src/resolvers/mutation/person/SignInMutationResolver.cjs.map +1 -1
  232. package/dist/development/src/resolvers/mutation/person/SignInMutationResolver.js +2 -1
  233. package/dist/development/src/resolvers/mutation/person/SignInMutationResolver.js.map +1 -1
  234. package/dist/development/src/resolvers/mutation/person/SignOutMutationResolver.cjs +2 -1
  235. package/dist/development/src/resolvers/mutation/person/SignOutMutationResolver.cjs.map +1 -1
  236. package/dist/development/src/resolvers/mutation/person/SignOutMutationResolver.js +2 -1
  237. package/dist/development/src/resolvers/mutation/person/SignOutMutationResolver.js.map +1 -1
  238. package/dist/development/src/resolvers/mutation/person/SignUpMutationResolver.cjs +2 -1
  239. package/dist/development/src/resolvers/mutation/person/SignUpMutationResolver.cjs.map +1 -1
  240. package/dist/development/src/resolvers/mutation/person/SignUpMutationResolver.js +2 -1
  241. package/dist/development/src/resolvers/mutation/person/SignUpMutationResolver.js.map +1 -1
  242. package/dist/development/src/resolvers/mutation/person/TogglePasswordlessMutationResolver.cjs +2 -1
  243. package/dist/development/src/resolvers/mutation/person/TogglePasswordlessMutationResolver.cjs.map +1 -1
  244. package/dist/development/src/resolvers/mutation/person/TogglePasswordlessMutationResolver.js +2 -1
  245. package/dist/development/src/resolvers/mutation/person/TogglePasswordlessMutationResolver.js.map +1 -1
  246. package/dist/development/src/resolvers/mutation/project/CreateProjectMutationResolver.cjs +2 -1
  247. package/dist/development/src/resolvers/mutation/project/CreateProjectMutationResolver.cjs.map +1 -1
  248. package/dist/development/src/resolvers/mutation/project/CreateProjectMutationResolver.js +2 -1
  249. package/dist/development/src/resolvers/mutation/project/CreateProjectMutationResolver.js.map +1 -1
  250. package/dist/development/src/resolvers/mutation/project/SetProjectSecretMutationResolver.cjs +2 -1
  251. package/dist/development/src/resolvers/mutation/project/SetProjectSecretMutationResolver.cjs.map +1 -1
  252. package/dist/development/src/resolvers/mutation/project/SetProjectSecretMutationResolver.js +2 -1
  253. package/dist/development/src/resolvers/mutation/project/SetProjectSecretMutationResolver.js.map +1 -1
  254. package/dist/development/src/resolvers/mutation/project/UpdateProjectMutationResolver.cjs +2 -1
  255. package/dist/development/src/resolvers/mutation/project/UpdateProjectMutationResolver.cjs.map +1 -1
  256. package/dist/development/src/resolvers/mutation/project/UpdateProjectMutationResolver.js +2 -1
  257. package/dist/development/src/resolvers/mutation/project/UpdateProjectMutationResolver.js.map +1 -1
  258. package/dist/development/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.cjs +2 -1
  259. package/dist/development/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.cjs.map +1 -1
  260. package/dist/development/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.js +2 -1
  261. package/dist/development/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.js.map +1 -1
  262. package/dist/development/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.cjs +2 -1
  263. package/dist/development/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.cjs.map +1 -1
  264. package/dist/development/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.js +2 -1
  265. package/dist/development/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.js.map +1 -1
  266. package/dist/development/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.cjs +2 -1
  267. package/dist/development/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.cjs.map +1 -1
  268. package/dist/development/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.js +2 -1
  269. package/dist/development/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.js.map +1 -1
  270. package/dist/development/src/resolvers/query/ApiKeyQueryResolver.cjs +2 -1
  271. package/dist/development/src/resolvers/query/ApiKeyQueryResolver.cjs.map +1 -1
  272. package/dist/development/src/resolvers/query/ApiKeyQueryResolver.js +2 -1
  273. package/dist/development/src/resolvers/query/ApiKeyQueryResolver.js.map +1 -1
  274. package/dist/development/src/resolvers/query/AuthLogQueryResolver.cjs +2 -1
  275. package/dist/development/src/resolvers/query/AuthLogQueryResolver.cjs.map +1 -1
  276. package/dist/development/src/resolvers/query/AuthLogQueryResolver.js +2 -1
  277. package/dist/development/src/resolvers/query/AuthLogQueryResolver.js.map +1 -1
  278. package/dist/development/src/resolvers/query/AuthPolicyQueryResolver.cjs +2 -1
  279. package/dist/development/src/resolvers/query/AuthPolicyQueryResolver.cjs.map +1 -1
  280. package/dist/development/src/resolvers/query/AuthPolicyQueryResolver.js +2 -1
  281. package/dist/development/src/resolvers/query/AuthPolicyQueryResolver.js.map +1 -1
  282. package/dist/development/src/resolvers/query/ConfigurationQueryResolver.cjs +2 -1
  283. package/dist/development/src/resolvers/query/ConfigurationQueryResolver.cjs.map +1 -1
  284. package/dist/development/src/resolvers/query/ConfigurationQueryResolver.js +2 -1
  285. package/dist/development/src/resolvers/query/ConfigurationQueryResolver.js.map +1 -1
  286. package/dist/development/src/resolvers/query/IDPQueryResolver.cjs +2 -1
  287. package/dist/development/src/resolvers/query/IDPQueryResolver.cjs.map +1 -1
  288. package/dist/development/src/resolvers/query/IDPQueryResolver.js +2 -1
  289. package/dist/development/src/resolvers/query/IDPQueryResolver.js.map +1 -1
  290. package/dist/development/src/resolvers/query/MailTemplateQueryResolver.cjs +2 -1
  291. package/dist/development/src/resolvers/query/MailTemplateQueryResolver.cjs.map +1 -1
  292. package/dist/development/src/resolvers/query/MailTemplateQueryResolver.js +2 -1
  293. package/dist/development/src/resolvers/query/MailTemplateQueryResolver.js.map +1 -1
  294. package/dist/development/src/resolvers/query/PersonQueryResolver.cjs +2 -1
  295. package/dist/development/src/resolvers/query/PersonQueryResolver.cjs.map +1 -1
  296. package/dist/development/src/resolvers/query/PersonQueryResolver.js +2 -1
  297. package/dist/development/src/resolvers/query/PersonQueryResolver.js.map +1 -1
  298. package/dist/development/src/resolvers/query/ProjectMembersQueryResolver.cjs +2 -1
  299. package/dist/development/src/resolvers/query/ProjectMembersQueryResolver.cjs.map +1 -1
  300. package/dist/development/src/resolvers/query/ProjectMembersQueryResolver.js +2 -1
  301. package/dist/development/src/resolvers/query/ProjectMembersQueryResolver.js.map +1 -1
  302. package/dist/development/src/resolvers/query/ProjectQueryResolver.cjs +5 -3
  303. package/dist/development/src/resolvers/query/ProjectQueryResolver.cjs.map +1 -1
  304. package/dist/development/src/resolvers/query/ProjectQueryResolver.js +5 -3
  305. package/dist/development/src/resolvers/query/ProjectQueryResolver.js.map +1 -1
  306. package/dist/development/src/resolvers/responseHelpers/ApiKeyResponseFactory.cjs +2 -1
  307. package/dist/development/src/resolvers/responseHelpers/ApiKeyResponseFactory.cjs.map +1 -1
  308. package/dist/development/src/resolvers/responseHelpers/ApiKeyResponseFactory.js +2 -1
  309. package/dist/development/src/resolvers/responseHelpers/ApiKeyResponseFactory.js.map +1 -1
  310. package/dist/development/src/resolvers/responseHelpers/PersonResponseFactory.cjs +5 -0
  311. package/dist/development/src/resolvers/responseHelpers/PersonResponseFactory.cjs.map +1 -1
  312. package/dist/development/src/resolvers/responseHelpers/PersonResponseFactory.js +5 -0
  313. package/dist/development/src/resolvers/responseHelpers/PersonResponseFactory.js.map +1 -1
  314. package/dist/development/src/resolvers/responseHelpers/ProjectResponseFactory.cjs +23 -0
  315. package/dist/development/src/resolvers/responseHelpers/ProjectResponseFactory.cjs.map +1 -0
  316. package/dist/development/src/resolvers/responseHelpers/ProjectResponseFactory.js +23 -0
  317. package/dist/development/src/resolvers/responseHelpers/ProjectResponseFactory.js.map +1 -0
  318. package/dist/development/src/resolvers/responseHelpers/SignInResponseFactory.cjs +2 -1
  319. package/dist/development/src/resolvers/responseHelpers/SignInResponseFactory.cjs.map +1 -1
  320. package/dist/development/src/resolvers/responseHelpers/SignInResponseFactory.js +2 -1
  321. package/dist/development/src/resolvers/responseHelpers/SignInResponseFactory.js.map +1 -1
  322. package/dist/development/src/resolvers/types/IdentityTypeResolver.cjs +37 -4
  323. package/dist/development/src/resolvers/types/IdentityTypeResolver.cjs.map +1 -1
  324. package/dist/development/src/resolvers/types/IdentityTypeResolver.js +37 -4
  325. package/dist/development/src/resolvers/types/IdentityTypeResolver.js.map +1 -1
  326. package/dist/development/src/resolvers/types/PersonTypeResolver.cjs +30 -1
  327. package/dist/development/src/resolvers/types/PersonTypeResolver.cjs.map +1 -1
  328. package/dist/development/src/resolvers/types/PersonTypeResolver.js +30 -1
  329. package/dist/development/src/resolvers/types/PersonTypeResolver.js.map +1 -1
  330. package/dist/development/src/resolvers/types/ProjectTypeResolver.cjs +25 -1
  331. package/dist/development/src/resolvers/types/ProjectTypeResolver.cjs.map +1 -1
  332. package/dist/development/src/resolvers/types/ProjectTypeResolver.js +25 -1
  333. package/dist/development/src/resolvers/types/ProjectTypeResolver.js.map +1 -1
  334. package/dist/development/src/schema/tenant.graphql.cjs +116 -0
  335. package/dist/development/src/schema/tenant.graphql.cjs.map +1 -1
  336. package/dist/development/src/schema/tenant.graphql.js +116 -0
  337. package/dist/development/src/schema/tenant.graphql.js.map +1 -1
  338. package/dist/production/index.cjs +30 -0
  339. package/dist/production/index.cjs.map +1 -1
  340. package/dist/production/index.js +31 -1
  341. package/dist/production/index.js.map +1 -1
  342. package/dist/production/src/TenantContainer.cjs +15 -3
  343. package/dist/production/src/TenantContainer.cjs.map +1 -1
  344. package/dist/production/src/TenantContainer.js +15 -3
  345. package/dist/production/src/TenantContainer.js.map +1 -1
  346. package/dist/production/src/bridges/system/IdentityFetcher.cjs +2 -1
  347. package/dist/production/src/bridges/system/IdentityFetcher.cjs.map +1 -1
  348. package/dist/production/src/bridges/system/IdentityFetcher.js +2 -1
  349. package/dist/production/src/bridges/system/IdentityFetcher.js.map +1 -1
  350. package/dist/production/src/migrations/2026-06-18-120000-idp-claim-mapping.cjs +10 -0
  351. package/dist/production/src/migrations/2026-06-18-120000-idp-claim-mapping.cjs.map +1 -0
  352. package/dist/production/src/migrations/2026-06-18-120000-idp-claim-mapping.js +11 -0
  353. package/dist/production/src/migrations/2026-06-18-120000-idp-claim-mapping.js.map +1 -0
  354. package/dist/production/src/migrations/2026-08-03-120000-person-enable-auth-log.cjs +9 -0
  355. package/dist/production/src/migrations/2026-08-03-120000-person-enable-auth-log.cjs.map +1 -0
  356. package/dist/production/src/migrations/2026-08-03-120000-person-enable-auth-log.js +10 -0
  357. package/dist/production/src/migrations/2026-08-03-120000-person-enable-auth-log.js.map +1 -0
  358. package/dist/production/src/migrations/2026-08-04-120000-config-panel.cjs +11 -0
  359. package/dist/production/src/migrations/2026-08-04-120000-config-panel.cjs.map +1 -0
  360. package/dist/production/src/migrations/2026-08-04-120000-config-panel.js +12 -0
  361. package/dist/production/src/migrations/2026-08-04-120000-config-panel.js.map +1 -0
  362. package/dist/production/src/migrations/runner.cjs +9 -2
  363. package/dist/production/src/migrations/runner.cjs.map +1 -1
  364. package/dist/production/src/migrations/runner.js +9 -2
  365. package/dist/production/src/migrations/runner.js.map +1 -1
  366. package/dist/production/src/migrations/snapshot.cjs +6 -1
  367. package/dist/production/src/migrations/snapshot.cjs.map +1 -1
  368. package/dist/production/src/migrations/snapshot.js +6 -1
  369. package/dist/production/src/migrations/snapshot.js.map +1 -1
  370. package/dist/production/src/model/commands/configuration/UpdateConfigurationCommand.cjs +5 -3
  371. package/dist/production/src/model/commands/configuration/UpdateConfigurationCommand.cjs.map +1 -1
  372. package/dist/production/src/model/commands/configuration/UpdateConfigurationCommand.js +5 -3
  373. package/dist/production/src/model/commands/configuration/UpdateConfigurationCommand.js.map +1 -1
  374. package/dist/production/src/model/commands/membership/{RemoveProjectMembershipsCommand.cjs → RemoveProjectMembershipCommand.cjs} +1 -1
  375. package/dist/production/src/model/commands/membership/RemoveProjectMembershipCommand.cjs.map +1 -0
  376. package/dist/production/src/model/commands/membership/{RemoveProjectMembershipsCommand.js → RemoveProjectMembershipCommand.js} +1 -1
  377. package/dist/production/src/model/commands/membership/RemoveProjectMembershipCommand.js.map +1 -0
  378. package/dist/production/src/model/commands/membership/UpdateProjectMemberCommand.cjs +2 -2
  379. package/dist/production/src/model/commands/membership/UpdateProjectMemberCommand.cjs.map +1 -1
  380. package/dist/production/src/model/commands/membership/UpdateProjectMemberCommand.js +1 -1
  381. package/dist/production/src/model/commands/membership/UpdateProjectMemberCommand.js.map +1 -1
  382. package/dist/production/src/model/commands/person/EnablePersonCommand.cjs +17 -0
  383. package/dist/production/src/model/commands/person/EnablePersonCommand.cjs.map +1 -0
  384. package/dist/production/src/model/commands/person/EnablePersonCommand.js +17 -0
  385. package/dist/production/src/model/commands/person/EnablePersonCommand.js.map +1 -0
  386. package/dist/production/src/model/queries/configuration/ConfigurationQuery.cjs +4 -0
  387. package/dist/production/src/model/queries/configuration/ConfigurationQuery.cjs.map +1 -1
  388. package/dist/production/src/model/queries/configuration/ConfigurationQuery.js +4 -0
  389. package/dist/production/src/model/queries/configuration/ConfigurationQuery.js.map +1 -1
  390. package/dist/production/src/model/queries/membership/ProjectMembersQuery.cjs +1 -1
  391. package/dist/production/src/model/queries/membership/ProjectMembersQuery.cjs.map +1 -1
  392. package/dist/production/src/model/queries/membership/ProjectMembersQuery.js +1 -1
  393. package/dist/production/src/model/queries/membership/ProjectMembersQuery.js.map +1 -1
  394. package/dist/production/src/model/queries/person/PersonQueryBuilderFactory.cjs +1 -1
  395. package/dist/production/src/model/queries/person/PersonQueryBuilderFactory.cjs.map +1 -1
  396. package/dist/production/src/model/queries/person/PersonQueryBuilderFactory.js +1 -1
  397. package/dist/production/src/model/queries/person/PersonQueryBuilderFactory.js.map +1 -1
  398. package/dist/production/src/model/service/AuthLogService.cjs +8 -2
  399. package/dist/production/src/model/service/AuthLogService.cjs.map +1 -1
  400. package/dist/production/src/model/service/AuthLogService.js +8 -2
  401. package/dist/production/src/model/service/AuthLogService.js.map +1 -1
  402. package/dist/production/src/model/service/IDPSignInManager.cjs +29 -2
  403. package/dist/production/src/model/service/IDPSignInManager.cjs.map +1 -1
  404. package/dist/production/src/model/service/IDPSignInManager.js +29 -2
  405. package/dist/production/src/model/service/IDPSignInManager.js.map +1 -1
  406. package/dist/production/src/model/service/PanelAccessResolver.cjs +31 -0
  407. package/dist/production/src/model/service/PanelAccessResolver.cjs.map +1 -0
  408. package/dist/production/src/model/service/PanelAccessResolver.js +31 -0
  409. package/dist/production/src/model/service/PanelAccessResolver.js.map +1 -0
  410. package/dist/production/src/model/service/PersonAccessManager.cjs +10 -2
  411. package/dist/production/src/model/service/PersonAccessManager.cjs.map +1 -1
  412. package/dist/production/src/model/service/PersonAccessManager.js +10 -2
  413. package/dist/production/src/model/service/PersonAccessManager.js.map +1 -1
  414. package/dist/production/src/model/service/apiKey/ApiKeyManager.cjs +4 -3
  415. package/dist/production/src/model/service/apiKey/ApiKeyManager.cjs.map +1 -1
  416. package/dist/production/src/model/service/apiKey/ApiKeyManager.js +4 -3
  417. package/dist/production/src/model/service/apiKey/ApiKeyManager.js.map +1 -1
  418. package/dist/production/src/model/service/apiKey/UnpersistedApiKeyManager.cjs +7 -0
  419. package/dist/production/src/model/service/apiKey/UnpersistedApiKeyManager.cjs.map +1 -1
  420. package/dist/production/src/model/service/apiKey/UnpersistedApiKeyManager.js +8 -1
  421. package/dist/production/src/model/service/apiKey/UnpersistedApiKeyManager.js.map +1 -1
  422. package/dist/production/src/model/service/idp/ClaimMapping.cjs +187 -0
  423. package/dist/production/src/model/service/idp/ClaimMapping.cjs.map +1 -0
  424. package/dist/production/src/model/service/idp/ClaimMapping.js +170 -0
  425. package/dist/production/src/model/service/idp/ClaimMapping.js.map +1 -0
  426. package/dist/production/src/model/service/idp/ClaimMappingEvaluator.cjs +155 -0
  427. package/dist/production/src/model/service/idp/ClaimMappingEvaluator.cjs.map +1 -0
  428. package/dist/production/src/model/service/idp/ClaimMappingEvaluator.js +155 -0
  429. package/dist/production/src/model/service/idp/ClaimMappingEvaluator.js.map +1 -0
  430. package/dist/production/src/model/service/idp/ClaimMappingValidation.cjs +83 -0
  431. package/dist/production/src/model/service/idp/ClaimMappingValidation.cjs.map +1 -0
  432. package/dist/production/src/model/service/idp/ClaimMappingValidation.js +83 -0
  433. package/dist/production/src/model/service/idp/ClaimMappingValidation.js.map +1 -0
  434. package/dist/production/src/model/service/idp/IDPClaimSyncService.cjs +260 -0
  435. package/dist/production/src/model/service/idp/IDPClaimSyncService.cjs.map +1 -0
  436. package/dist/production/src/model/service/idp/IDPClaimSyncService.js +260 -0
  437. package/dist/production/src/model/service/idp/IDPClaimSyncService.js.map +1 -0
  438. package/dist/production/src/model/service/idp/IDPManager.cjs +96 -20
  439. package/dist/production/src/model/service/idp/IDPManager.cjs.map +1 -1
  440. package/dist/production/src/model/service/idp/IDPManager.js +96 -20
  441. package/dist/production/src/model/service/idp/IDPManager.js.map +1 -1
  442. package/dist/production/src/model/service/idp/IdpSessionRevalidator.cjs +55 -1
  443. package/dist/production/src/model/service/idp/IdpSessionRevalidator.cjs.map +1 -1
  444. package/dist/production/src/model/service/idp/IdpSessionRevalidator.js +55 -1
  445. package/dist/production/src/model/service/idp/IdpSessionRevalidator.js.map +1 -1
  446. package/dist/production/src/model/service/idp/providers/OIDCHelpers.cjs +69 -33
  447. package/dist/production/src/model/service/idp/providers/OIDCHelpers.cjs.map +1 -1
  448. package/dist/production/src/model/service/idp/providers/OIDCHelpers.js +69 -33
  449. package/dist/production/src/model/service/idp/providers/OIDCHelpers.js.map +1 -1
  450. package/dist/production/src/model/service/idp/providers/OIDCProvider.cjs +4 -1
  451. package/dist/production/src/model/service/idp/providers/OIDCProvider.cjs.map +1 -1
  452. package/dist/production/src/model/service/idp/providers/OIDCProvider.js +4 -1
  453. package/dist/production/src/model/service/idp/providers/OIDCProvider.js.map +1 -1
  454. package/dist/production/src/model/utils/DatabaseContext.cjs +7 -2
  455. package/dist/production/src/model/utils/DatabaseContext.cjs.map +1 -1
  456. package/dist/production/src/model/utils/DatabaseContext.js +8 -3
  457. package/dist/production/src/model/utils/DatabaseContext.js.map +1 -1
  458. package/dist/production/src/resolvers/ResolverFactory.cjs +6 -2
  459. package/dist/production/src/resolvers/ResolverFactory.cjs.map +1 -1
  460. package/dist/production/src/resolvers/ResolverFactory.js +6 -2
  461. package/dist/production/src/resolvers/ResolverFactory.js.map +1 -1
  462. package/dist/production/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.cjs +2 -1
  463. package/dist/production/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.cjs.map +1 -1
  464. package/dist/production/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.js +2 -1
  465. package/dist/production/src/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.js.map +1 -1
  466. package/dist/production/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.cjs +2 -1
  467. package/dist/production/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.cjs.map +1 -1
  468. package/dist/production/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.js +2 -1
  469. package/dist/production/src/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.js.map +1 -1
  470. package/dist/production/src/resolvers/mutation/configuration/AuthPolicyMutationResolver.cjs +2 -1
  471. package/dist/production/src/resolvers/mutation/configuration/AuthPolicyMutationResolver.cjs.map +1 -1
  472. package/dist/production/src/resolvers/mutation/configuration/AuthPolicyMutationResolver.js +2 -1
  473. package/dist/production/src/resolvers/mutation/configuration/AuthPolicyMutationResolver.js.map +1 -1
  474. package/dist/production/src/resolvers/mutation/configuration/ConfigurationMutationResolver.cjs +2 -1
  475. package/dist/production/src/resolvers/mutation/configuration/ConfigurationMutationResolver.cjs.map +1 -1
  476. package/dist/production/src/resolvers/mutation/configuration/ConfigurationMutationResolver.js +2 -1
  477. package/dist/production/src/resolvers/mutation/configuration/ConfigurationMutationResolver.js.map +1 -1
  478. package/dist/production/src/resolvers/mutation/identity/GlobalRolesMutationResolver.cjs +2 -1
  479. package/dist/production/src/resolvers/mutation/identity/GlobalRolesMutationResolver.cjs.map +1 -1
  480. package/dist/production/src/resolvers/mutation/identity/GlobalRolesMutationResolver.js +2 -1
  481. package/dist/production/src/resolvers/mutation/identity/GlobalRolesMutationResolver.js.map +1 -1
  482. package/dist/production/src/resolvers/mutation/idp/AddIDPMutationResolver.cjs +2 -1
  483. package/dist/production/src/resolvers/mutation/idp/AddIDPMutationResolver.cjs.map +1 -1
  484. package/dist/production/src/resolvers/mutation/idp/AddIDPMutationResolver.js +2 -1
  485. package/dist/production/src/resolvers/mutation/idp/AddIDPMutationResolver.js.map +1 -1
  486. package/dist/production/src/resolvers/mutation/idp/DisableIDPMutationResolver.cjs +2 -1
  487. package/dist/production/src/resolvers/mutation/idp/DisableIDPMutationResolver.cjs.map +1 -1
  488. package/dist/production/src/resolvers/mutation/idp/DisableIDPMutationResolver.js +2 -1
  489. package/dist/production/src/resolvers/mutation/idp/DisableIDPMutationResolver.js.map +1 -1
  490. package/dist/production/src/resolvers/mutation/idp/DisconnectMyIdentityProviderMutationResolver.cjs +2 -1
  491. package/dist/production/src/resolvers/mutation/idp/DisconnectMyIdentityProviderMutationResolver.cjs.map +1 -1
  492. package/dist/production/src/resolvers/mutation/idp/DisconnectMyIdentityProviderMutationResolver.js +2 -1
  493. package/dist/production/src/resolvers/mutation/idp/DisconnectMyIdentityProviderMutationResolver.js.map +1 -1
  494. package/dist/production/src/resolvers/mutation/idp/EnableIDPMutationResolver.cjs +2 -1
  495. package/dist/production/src/resolvers/mutation/idp/EnableIDPMutationResolver.cjs.map +1 -1
  496. package/dist/production/src/resolvers/mutation/idp/EnableIDPMutationResolver.js +2 -1
  497. package/dist/production/src/resolvers/mutation/idp/EnableIDPMutationResolver.js.map +1 -1
  498. package/dist/production/src/resolvers/mutation/idp/UpdateIDPMutationResolver.cjs +2 -1
  499. package/dist/production/src/resolvers/mutation/idp/UpdateIDPMutationResolver.cjs.map +1 -1
  500. package/dist/production/src/resolvers/mutation/idp/UpdateIDPMutationResolver.js +2 -1
  501. package/dist/production/src/resolvers/mutation/idp/UpdateIDPMutationResolver.js.map +1 -1
  502. package/dist/production/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.cjs +2 -1
  503. package/dist/production/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.cjs.map +1 -1
  504. package/dist/production/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.js +2 -1
  505. package/dist/production/src/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.js.map +1 -1
  506. package/dist/production/src/resolvers/mutation/person/ChangePasswordMutationResolver.cjs +2 -1
  507. package/dist/production/src/resolvers/mutation/person/ChangePasswordMutationResolver.cjs.map +1 -1
  508. package/dist/production/src/resolvers/mutation/person/ChangePasswordMutationResolver.js +2 -1
  509. package/dist/production/src/resolvers/mutation/person/ChangePasswordMutationResolver.js.map +1 -1
  510. package/dist/production/src/resolvers/mutation/person/ChangeProfileMutationResolver.cjs +2 -1
  511. package/dist/production/src/resolvers/mutation/person/ChangeProfileMutationResolver.cjs.map +1 -1
  512. package/dist/production/src/resolvers/mutation/person/ChangeProfileMutationResolver.js +2 -1
  513. package/dist/production/src/resolvers/mutation/person/ChangeProfileMutationResolver.js.map +1 -1
  514. package/dist/production/src/resolvers/mutation/person/DisablePersonMutationResolver.cjs +4 -3
  515. package/dist/production/src/resolvers/mutation/person/DisablePersonMutationResolver.cjs.map +1 -1
  516. package/dist/production/src/resolvers/mutation/person/DisablePersonMutationResolver.js +4 -3
  517. package/dist/production/src/resolvers/mutation/person/DisablePersonMutationResolver.js.map +1 -1
  518. package/dist/production/src/resolvers/mutation/person/EmailOtpMutationResolver.cjs +2 -1
  519. package/dist/production/src/resolvers/mutation/person/EmailOtpMutationResolver.cjs.map +1 -1
  520. package/dist/production/src/resolvers/mutation/person/EmailOtpMutationResolver.js +2 -1
  521. package/dist/production/src/resolvers/mutation/person/EmailOtpMutationResolver.js.map +1 -1
  522. package/dist/production/src/resolvers/mutation/person/EmailVerificationMutationResolver.cjs +2 -1
  523. package/dist/production/src/resolvers/mutation/person/EmailVerificationMutationResolver.cjs.map +1 -1
  524. package/dist/production/src/resolvers/mutation/person/EmailVerificationMutationResolver.js +2 -1
  525. package/dist/production/src/resolvers/mutation/person/EmailVerificationMutationResolver.js.map +1 -1
  526. package/dist/production/src/resolvers/mutation/person/EnablePersonMutationResolver.cjs +60 -0
  527. package/dist/production/src/resolvers/mutation/person/EnablePersonMutationResolver.cjs.map +1 -0
  528. package/dist/production/src/resolvers/mutation/person/EnablePersonMutationResolver.js +60 -0
  529. package/dist/production/src/resolvers/mutation/person/EnablePersonMutationResolver.js.map +1 -0
  530. package/dist/production/src/resolvers/mutation/person/ForceSignOutMutationResolver.cjs +2 -1
  531. package/dist/production/src/resolvers/mutation/person/ForceSignOutMutationResolver.cjs.map +1 -1
  532. package/dist/production/src/resolvers/mutation/person/ForceSignOutMutationResolver.js +2 -1
  533. package/dist/production/src/resolvers/mutation/person/ForceSignOutMutationResolver.js.map +1 -1
  534. package/dist/production/src/resolvers/mutation/person/IDPMutationResolver.cjs +27 -1
  535. package/dist/production/src/resolvers/mutation/person/IDPMutationResolver.cjs.map +1 -1
  536. package/dist/production/src/resolvers/mutation/person/IDPMutationResolver.js +27 -1
  537. package/dist/production/src/resolvers/mutation/person/IDPMutationResolver.js.map +1 -1
  538. package/dist/production/src/resolvers/mutation/person/InviteMutationResolver.cjs +2 -1
  539. package/dist/production/src/resolvers/mutation/person/InviteMutationResolver.cjs.map +1 -1
  540. package/dist/production/src/resolvers/mutation/person/InviteMutationResolver.js +2 -1
  541. package/dist/production/src/resolvers/mutation/person/InviteMutationResolver.js.map +1 -1
  542. package/dist/production/src/resolvers/mutation/person/OtpMutationResolver.cjs +2 -1
  543. package/dist/production/src/resolvers/mutation/person/OtpMutationResolver.cjs.map +1 -1
  544. package/dist/production/src/resolvers/mutation/person/OtpMutationResolver.js +2 -1
  545. package/dist/production/src/resolvers/mutation/person/OtpMutationResolver.js.map +1 -1
  546. package/dist/production/src/resolvers/mutation/person/PasswordlessMutationResolver.cjs +2 -1
  547. package/dist/production/src/resolvers/mutation/person/PasswordlessMutationResolver.cjs.map +1 -1
  548. package/dist/production/src/resolvers/mutation/person/PasswordlessMutationResolver.js +2 -1
  549. package/dist/production/src/resolvers/mutation/person/PasswordlessMutationResolver.js.map +1 -1
  550. package/dist/production/src/resolvers/mutation/person/RegenerateBackupCodesMutationResolver.cjs +2 -1
  551. package/dist/production/src/resolvers/mutation/person/RegenerateBackupCodesMutationResolver.cjs.map +1 -1
  552. package/dist/production/src/resolvers/mutation/person/RegenerateBackupCodesMutationResolver.js +2 -1
  553. package/dist/production/src/resolvers/mutation/person/RegenerateBackupCodesMutationResolver.js.map +1 -1
  554. package/dist/production/src/resolvers/mutation/person/ResetPasswordMutationResolver.cjs +2 -1
  555. package/dist/production/src/resolvers/mutation/person/ResetPasswordMutationResolver.cjs.map +1 -1
  556. package/dist/production/src/resolvers/mutation/person/ResetPasswordMutationResolver.js +2 -1
  557. package/dist/production/src/resolvers/mutation/person/ResetPasswordMutationResolver.js.map +1 -1
  558. package/dist/production/src/resolvers/mutation/person/ResetPersonMfaMutationResolver.cjs +2 -1
  559. package/dist/production/src/resolvers/mutation/person/ResetPersonMfaMutationResolver.cjs.map +1 -1
  560. package/dist/production/src/resolvers/mutation/person/ResetPersonMfaMutationResolver.js +2 -1
  561. package/dist/production/src/resolvers/mutation/person/ResetPersonMfaMutationResolver.js.map +1 -1
  562. package/dist/production/src/resolvers/mutation/person/RevokeSessionMutationResolver.cjs +2 -1
  563. package/dist/production/src/resolvers/mutation/person/RevokeSessionMutationResolver.cjs.map +1 -1
  564. package/dist/production/src/resolvers/mutation/person/RevokeSessionMutationResolver.js +2 -1
  565. package/dist/production/src/resolvers/mutation/person/RevokeSessionMutationResolver.js.map +1 -1
  566. package/dist/production/src/resolvers/mutation/person/SignInMutationResolver.cjs +2 -1
  567. package/dist/production/src/resolvers/mutation/person/SignInMutationResolver.cjs.map +1 -1
  568. package/dist/production/src/resolvers/mutation/person/SignInMutationResolver.js +2 -1
  569. package/dist/production/src/resolvers/mutation/person/SignInMutationResolver.js.map +1 -1
  570. package/dist/production/src/resolvers/mutation/person/SignOutMutationResolver.cjs +2 -1
  571. package/dist/production/src/resolvers/mutation/person/SignOutMutationResolver.cjs.map +1 -1
  572. package/dist/production/src/resolvers/mutation/person/SignOutMutationResolver.js +2 -1
  573. package/dist/production/src/resolvers/mutation/person/SignOutMutationResolver.js.map +1 -1
  574. package/dist/production/src/resolvers/mutation/person/SignUpMutationResolver.cjs +2 -1
  575. package/dist/production/src/resolvers/mutation/person/SignUpMutationResolver.cjs.map +1 -1
  576. package/dist/production/src/resolvers/mutation/person/SignUpMutationResolver.js +2 -1
  577. package/dist/production/src/resolvers/mutation/person/SignUpMutationResolver.js.map +1 -1
  578. package/dist/production/src/resolvers/mutation/person/TogglePasswordlessMutationResolver.cjs +2 -1
  579. package/dist/production/src/resolvers/mutation/person/TogglePasswordlessMutationResolver.cjs.map +1 -1
  580. package/dist/production/src/resolvers/mutation/person/TogglePasswordlessMutationResolver.js +2 -1
  581. package/dist/production/src/resolvers/mutation/person/TogglePasswordlessMutationResolver.js.map +1 -1
  582. package/dist/production/src/resolvers/mutation/project/CreateProjectMutationResolver.cjs +2 -1
  583. package/dist/production/src/resolvers/mutation/project/CreateProjectMutationResolver.cjs.map +1 -1
  584. package/dist/production/src/resolvers/mutation/project/CreateProjectMutationResolver.js +2 -1
  585. package/dist/production/src/resolvers/mutation/project/CreateProjectMutationResolver.js.map +1 -1
  586. package/dist/production/src/resolvers/mutation/project/SetProjectSecretMutationResolver.cjs +2 -1
  587. package/dist/production/src/resolvers/mutation/project/SetProjectSecretMutationResolver.cjs.map +1 -1
  588. package/dist/production/src/resolvers/mutation/project/SetProjectSecretMutationResolver.js +2 -1
  589. package/dist/production/src/resolvers/mutation/project/SetProjectSecretMutationResolver.js.map +1 -1
  590. package/dist/production/src/resolvers/mutation/project/UpdateProjectMutationResolver.cjs +2 -1
  591. package/dist/production/src/resolvers/mutation/project/UpdateProjectMutationResolver.cjs.map +1 -1
  592. package/dist/production/src/resolvers/mutation/project/UpdateProjectMutationResolver.js +2 -1
  593. package/dist/production/src/resolvers/mutation/project/UpdateProjectMutationResolver.js.map +1 -1
  594. package/dist/production/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.cjs +2 -1
  595. package/dist/production/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.cjs.map +1 -1
  596. package/dist/production/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.js +2 -1
  597. package/dist/production/src/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.js.map +1 -1
  598. package/dist/production/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.cjs +2 -1
  599. package/dist/production/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.cjs.map +1 -1
  600. package/dist/production/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.js +2 -1
  601. package/dist/production/src/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.js.map +1 -1
  602. package/dist/production/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.cjs +2 -1
  603. package/dist/production/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.cjs.map +1 -1
  604. package/dist/production/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.js +2 -1
  605. package/dist/production/src/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.js.map +1 -1
  606. package/dist/production/src/resolvers/query/ApiKeyQueryResolver.cjs +2 -1
  607. package/dist/production/src/resolvers/query/ApiKeyQueryResolver.cjs.map +1 -1
  608. package/dist/production/src/resolvers/query/ApiKeyQueryResolver.js +2 -1
  609. package/dist/production/src/resolvers/query/ApiKeyQueryResolver.js.map +1 -1
  610. package/dist/production/src/resolvers/query/AuthLogQueryResolver.cjs +2 -1
  611. package/dist/production/src/resolvers/query/AuthLogQueryResolver.cjs.map +1 -1
  612. package/dist/production/src/resolvers/query/AuthLogQueryResolver.js +2 -1
  613. package/dist/production/src/resolvers/query/AuthLogQueryResolver.js.map +1 -1
  614. package/dist/production/src/resolvers/query/AuthPolicyQueryResolver.cjs +2 -1
  615. package/dist/production/src/resolvers/query/AuthPolicyQueryResolver.cjs.map +1 -1
  616. package/dist/production/src/resolvers/query/AuthPolicyQueryResolver.js +2 -1
  617. package/dist/production/src/resolvers/query/AuthPolicyQueryResolver.js.map +1 -1
  618. package/dist/production/src/resolvers/query/ConfigurationQueryResolver.cjs +2 -1
  619. package/dist/production/src/resolvers/query/ConfigurationQueryResolver.cjs.map +1 -1
  620. package/dist/production/src/resolvers/query/ConfigurationQueryResolver.js +2 -1
  621. package/dist/production/src/resolvers/query/ConfigurationQueryResolver.js.map +1 -1
  622. package/dist/production/src/resolvers/query/IDPQueryResolver.cjs +2 -1
  623. package/dist/production/src/resolvers/query/IDPQueryResolver.cjs.map +1 -1
  624. package/dist/production/src/resolvers/query/IDPQueryResolver.js +2 -1
  625. package/dist/production/src/resolvers/query/IDPQueryResolver.js.map +1 -1
  626. package/dist/production/src/resolvers/query/MailTemplateQueryResolver.cjs +2 -1
  627. package/dist/production/src/resolvers/query/MailTemplateQueryResolver.cjs.map +1 -1
  628. package/dist/production/src/resolvers/query/MailTemplateQueryResolver.js +2 -1
  629. package/dist/production/src/resolvers/query/MailTemplateQueryResolver.js.map +1 -1
  630. package/dist/production/src/resolvers/query/PersonQueryResolver.cjs +2 -1
  631. package/dist/production/src/resolvers/query/PersonQueryResolver.cjs.map +1 -1
  632. package/dist/production/src/resolvers/query/PersonQueryResolver.js +2 -1
  633. package/dist/production/src/resolvers/query/PersonQueryResolver.js.map +1 -1
  634. package/dist/production/src/resolvers/query/ProjectMembersQueryResolver.cjs +2 -1
  635. package/dist/production/src/resolvers/query/ProjectMembersQueryResolver.cjs.map +1 -1
  636. package/dist/production/src/resolvers/query/ProjectMembersQueryResolver.js +2 -1
  637. package/dist/production/src/resolvers/query/ProjectMembersQueryResolver.js.map +1 -1
  638. package/dist/production/src/resolvers/query/ProjectQueryResolver.cjs +5 -3
  639. package/dist/production/src/resolvers/query/ProjectQueryResolver.cjs.map +1 -1
  640. package/dist/production/src/resolvers/query/ProjectQueryResolver.js +5 -3
  641. package/dist/production/src/resolvers/query/ProjectQueryResolver.js.map +1 -1
  642. package/dist/production/src/resolvers/responseHelpers/ApiKeyResponseFactory.cjs +2 -1
  643. package/dist/production/src/resolvers/responseHelpers/ApiKeyResponseFactory.cjs.map +1 -1
  644. package/dist/production/src/resolvers/responseHelpers/ApiKeyResponseFactory.js +2 -1
  645. package/dist/production/src/resolvers/responseHelpers/ApiKeyResponseFactory.js.map +1 -1
  646. package/dist/production/src/resolvers/responseHelpers/PersonResponseFactory.cjs +5 -0
  647. package/dist/production/src/resolvers/responseHelpers/PersonResponseFactory.cjs.map +1 -1
  648. package/dist/production/src/resolvers/responseHelpers/PersonResponseFactory.js +5 -0
  649. package/dist/production/src/resolvers/responseHelpers/PersonResponseFactory.js.map +1 -1
  650. package/dist/production/src/resolvers/responseHelpers/ProjectResponseFactory.cjs +23 -0
  651. package/dist/production/src/resolvers/responseHelpers/ProjectResponseFactory.cjs.map +1 -0
  652. package/dist/production/src/resolvers/responseHelpers/ProjectResponseFactory.js +23 -0
  653. package/dist/production/src/resolvers/responseHelpers/ProjectResponseFactory.js.map +1 -0
  654. package/dist/production/src/resolvers/responseHelpers/SignInResponseFactory.cjs +2 -1
  655. package/dist/production/src/resolvers/responseHelpers/SignInResponseFactory.cjs.map +1 -1
  656. package/dist/production/src/resolvers/responseHelpers/SignInResponseFactory.js +2 -1
  657. package/dist/production/src/resolvers/responseHelpers/SignInResponseFactory.js.map +1 -1
  658. package/dist/production/src/resolvers/types/IdentityTypeResolver.cjs +37 -4
  659. package/dist/production/src/resolvers/types/IdentityTypeResolver.cjs.map +1 -1
  660. package/dist/production/src/resolvers/types/IdentityTypeResolver.js +37 -4
  661. package/dist/production/src/resolvers/types/IdentityTypeResolver.js.map +1 -1
  662. package/dist/production/src/resolvers/types/PersonTypeResolver.cjs +30 -1
  663. package/dist/production/src/resolvers/types/PersonTypeResolver.cjs.map +1 -1
  664. package/dist/production/src/resolvers/types/PersonTypeResolver.js +30 -1
  665. package/dist/production/src/resolvers/types/PersonTypeResolver.js.map +1 -1
  666. package/dist/production/src/resolvers/types/ProjectTypeResolver.cjs +25 -1
  667. package/dist/production/src/resolvers/types/ProjectTypeResolver.cjs.map +1 -1
  668. package/dist/production/src/resolvers/types/ProjectTypeResolver.js +25 -1
  669. package/dist/production/src/resolvers/types/ProjectTypeResolver.js.map +1 -1
  670. package/dist/production/src/schema/tenant.graphql.cjs +116 -0
  671. package/dist/production/src/schema/tenant.graphql.cjs.map +1 -1
  672. package/dist/production/src/schema/tenant.graphql.js +116 -0
  673. package/dist/production/src/schema/tenant.graphql.js.map +1 -1
  674. package/dist/tests/cases/integration/mocked/configurationPanel.test.d.ts +2 -0
  675. package/dist/tests/cases/integration/mocked/configurationPanel.test.d.ts.map +1 -0
  676. package/dist/tests/cases/integration/mocked/disablePersonMutation.test.d.ts +2 -0
  677. package/dist/tests/cases/integration/mocked/disablePersonMutation.test.d.ts.map +1 -0
  678. package/dist/tests/cases/integration/mocked/enablePersonMutation.test.d.ts +2 -0
  679. package/dist/tests/cases/integration/mocked/enablePersonMutation.test.d.ts.map +1 -0
  680. package/dist/tests/cases/integration/mocked/gql/addProjectMember.d.ts.map +1 -1
  681. package/dist/tests/cases/integration/mocked/gql/changeMyPassword.d.ts.map +1 -1
  682. package/dist/tests/cases/integration/mocked/gql/changeMyProfile.d.ts.map +1 -1
  683. package/dist/tests/cases/integration/mocked/gql/changePassword.d.ts.map +1 -1
  684. package/dist/tests/cases/integration/mocked/gql/changeProfile.d.ts.map +1 -1
  685. package/dist/tests/cases/integration/mocked/gql/confirmOtp.d.ts.map +1 -1
  686. package/dist/tests/cases/integration/mocked/gql/createApiKey.d.ts.map +1 -1
  687. package/dist/tests/cases/integration/mocked/gql/createResetPasswordRequest.d.ts.map +1 -1
  688. package/dist/tests/cases/integration/mocked/gql/createSessionToken.d.ts.map +1 -1
  689. package/dist/tests/cases/integration/mocked/gql/emailOtp.d.ts.map +1 -1
  690. package/dist/tests/cases/integration/mocked/gql/emailVerification.d.ts.map +1 -1
  691. package/dist/tests/cases/integration/mocked/gql/invite.d.ts.map +1 -1
  692. package/dist/tests/cases/integration/mocked/gql/myIdentityProviders.d.ts.map +1 -1
  693. package/dist/tests/cases/integration/mocked/gql/passwordless.d.ts +1 -1
  694. package/dist/tests/cases/integration/mocked/gql/passwordless.d.ts.map +1 -1
  695. package/dist/tests/cases/integration/mocked/gql/prepareOtp.d.ts.map +1 -1
  696. package/dist/tests/cases/integration/mocked/gql/resetPassword.d.ts.map +1 -1
  697. package/dist/tests/cases/integration/mocked/gql/signIn.d.ts.map +1 -1
  698. package/dist/tests/cases/integration/mocked/gql/signInIdp.d.ts.map +1 -1
  699. package/dist/tests/cases/integration/mocked/gql/signUp.d.ts.map +1 -1
  700. package/dist/tests/cases/integration/mocked/gql/unmanagedInvite.d.ts.map +1 -1
  701. package/dist/tests/cases/integration/mocked/gql/updateProjectMember.d.ts.map +1 -1
  702. package/dist/tests/cases/integration/mocked/idpClaimMappingConfig.test.d.ts +2 -0
  703. package/dist/tests/cases/integration/mocked/idpClaimMappingConfig.test.d.ts.map +1 -0
  704. package/dist/tests/cases/integration/mocked/permissionsQuery.test.d.ts +2 -0
  705. package/dist/tests/cases/integration/mocked/permissionsQuery.test.d.ts.map +1 -0
  706. package/dist/tests/cases/integration/mocked/signInIdpClaimMapping.test.d.ts +2 -0
  707. package/dist/tests/cases/integration/mocked/signInIdpClaimMapping.test.d.ts.map +1 -0
  708. package/dist/tests/cases/integration/mocked/signInIdpClaimMappingFixes.test.d.ts +2 -0
  709. package/dist/tests/cases/integration/mocked/signInIdpClaimMappingFixes.test.d.ts.map +1 -0
  710. package/dist/tests/cases/integration/mocked/signInIdpClaimMappingSafety.test.d.ts +2 -0
  711. package/dist/tests/cases/integration/mocked/signInIdpClaimMappingSafety.test.d.ts.map +1 -0
  712. package/dist/tests/cases/integration/mocked/sql/authLogSql.d.ts.map +1 -1
  713. package/dist/tests/cases/integration/mocked/sql/authPolicySql.d.ts.map +1 -1
  714. package/dist/tests/cases/integration/mocked/sql/consumeBackupCodeSql.d.ts.map +1 -1
  715. package/dist/tests/cases/integration/mocked/sql/createApiKeySql.d.ts.map +1 -1
  716. package/dist/tests/cases/integration/mocked/sql/createIdentitySql.d.ts.map +1 -1
  717. package/dist/tests/cases/integration/mocked/sql/createMembershipSql.d.ts.map +1 -1
  718. package/dist/tests/cases/integration/mocked/sql/createMembershipVariableSql.d.ts.map +1 -1
  719. package/dist/tests/cases/integration/mocked/sql/createPersonSql.d.ts.map +1 -1
  720. package/dist/tests/cases/integration/mocked/sql/createPersonTokenSql.d.ts.map +1 -1
  721. package/dist/tests/cases/integration/mocked/sql/createSessionKeySql.d.ts.map +1 -1
  722. package/dist/tests/cases/integration/mocked/sql/disableApiKeySql.d.ts.map +1 -1
  723. package/dist/tests/cases/integration/mocked/sql/disableOneOffKeySql.d.ts.map +1 -1
  724. package/dist/tests/cases/integration/mocked/sql/emailOtpSql.d.ts.map +1 -1
  725. package/dist/tests/cases/integration/mocked/sql/generateBackupCodesSql.d.ts.map +1 -1
  726. package/dist/tests/cases/integration/mocked/sql/getApiKeySql.d.ts.map +1 -1
  727. package/dist/tests/cases/integration/mocked/sql/getConfigSql.d.ts.map +1 -1
  728. package/dist/tests/cases/integration/mocked/sql/getIdentityByIdSql.d.ts.map +1 -1
  729. package/dist/tests/cases/integration/mocked/sql/getIdentityProjectsSql.d.ts.map +1 -1
  730. package/dist/tests/cases/integration/mocked/sql/getIdpBySlugSql.d.ts.map +1 -1
  731. package/dist/tests/cases/integration/mocked/sql/getIdpSessionByApiKeySql.d.ts.map +1 -1
  732. package/dist/tests/cases/integration/mocked/sql/getMailTemplateSql.d.ts.map +1 -1
  733. package/dist/tests/cases/integration/mocked/sql/getNextLoginAttemptSql.d.ts.map +1 -1
  734. package/dist/tests/cases/integration/mocked/sql/getNextMailAttemptSql.d.ts +1 -1
  735. package/dist/tests/cases/integration/mocked/sql/getNextMailAttemptSql.d.ts.map +1 -1
  736. package/dist/tests/cases/integration/mocked/sql/getPersonByEmailSql.d.ts.map +1 -1
  737. package/dist/tests/cases/integration/mocked/sql/getPersonByIdSql.d.ts.map +1 -1
  738. package/dist/tests/cases/integration/mocked/sql/getPersonByIdentity.d.ts.map +1 -1
  739. package/dist/tests/cases/integration/mocked/sql/getPersonByIdpSql.d.ts.map +1 -1
  740. package/dist/tests/cases/integration/mocked/sql/getPersonsByIdentitySql.d.ts.map +1 -1
  741. package/dist/tests/cases/integration/mocked/sql/getProjectBySlugSql.d.ts +1 -1
  742. package/dist/tests/cases/integration/mocked/sql/getProjectBySlugSql.d.ts.map +1 -1
  743. package/dist/tests/cases/integration/mocked/sql/getProjectMembershipSql.d.ts.map +1 -1
  744. package/dist/tests/cases/integration/mocked/sql/listApiKeysSql.d.ts.map +1 -1
  745. package/dist/tests/cases/integration/mocked/sql/listPersonsSql.d.ts +2 -0
  746. package/dist/tests/cases/integration/mocked/sql/listPersonsSql.d.ts.map +1 -1
  747. package/dist/tests/cases/integration/mocked/sql/listProjectSecretsSql.d.ts.map +1 -1
  748. package/dist/tests/cases/integration/mocked/sql/listSessionsSql.d.ts.map +1 -1
  749. package/dist/tests/cases/integration/mocked/sql/loginHistorySql.d.ts.map +1 -1
  750. package/dist/tests/cases/integration/mocked/sql/patchVariablesSql.d.ts.map +1 -1
  751. package/dist/tests/cases/integration/mocked/sql/personIdentityProvidersSql.d.ts.map +1 -1
  752. package/dist/tests/cases/integration/mocked/sql/removeMembershipSql.d.ts +8 -0
  753. package/dist/tests/cases/integration/mocked/sql/removeMembershipSql.d.ts.map +1 -0
  754. package/dist/tests/cases/integration/mocked/sql/selectMembershipsSql.d.ts.map +1 -1
  755. package/dist/tests/cases/integration/mocked/sql/setEmailOtpEnabledSql.d.ts.map +1 -1
  756. package/dist/tests/cases/integration/mocked/sql/sqlTransaction.d.ts.map +1 -1
  757. package/dist/tests/cases/integration/mocked/sql/updatePesonNameSql.d.ts.map +1 -1
  758. package/dist/tests/cases/integration/mocked/sql/updatePesonPasswordSql.d.ts.map +1 -1
  759. package/dist/tests/cases/unit/databaseContextRetry.test.d.ts +2 -0
  760. package/dist/tests/cases/unit/databaseContextRetry.test.d.ts.map +1 -0
  761. package/dist/tests/cases/unit/idp/claimMappingEvaluator.test.d.ts +2 -0
  762. package/dist/tests/cases/unit/idp/claimMappingEvaluator.test.d.ts.map +1 -0
  763. package/dist/tests/cases/unit/idp/claimMappingValidation.test.d.ts +2 -0
  764. package/dist/tests/cases/unit/idp/claimMappingValidation.test.d.ts.map +1 -0
  765. package/dist/tests/cases/unit/idp/idpManagerConfigMerge.test.d.ts +2 -0
  766. package/dist/tests/cases/unit/idp/idpManagerConfigMerge.test.d.ts.map +1 -0
  767. package/dist/tests/cases/unit/idp/idpManagerUnknownConfigKeys.test.d.ts +2 -0
  768. package/dist/tests/cases/unit/idp/idpManagerUnknownConfigKeys.test.d.ts.map +1 -0
  769. package/dist/tests/cases/unit/idp/oidcClaims.test.d.ts +2 -0
  770. package/dist/tests/cases/unit/idp/oidcClaims.test.d.ts.map +1 -0
  771. package/dist/tests/cases/unit/panelAccessResolver.test.d.ts +2 -0
  772. package/dist/tests/cases/unit/panelAccessResolver.test.d.ts.map +1 -0
  773. package/dist/tests/cases/unit/updateConfigurationCommand.test.d.ts +2 -0
  774. package/dist/tests/cases/unit/updateConfigurationCommand.test.d.ts.map +1 -0
  775. package/dist/tests/src/IdPMock.d.ts.map +1 -1
  776. package/dist/tests/src/dbUtils.d.ts.map +1 -1
  777. package/dist/tests/src/tags.d.ts.map +1 -1
  778. package/dist/tests/src/testGraphql.d.ts.map +1 -1
  779. package/dist/tests/src/testTenant.d.ts +7 -1
  780. package/dist/tests/src/testTenant.d.ts.map +1 -1
  781. package/dist/tests/src/testUuid.d.ts.map +1 -1
  782. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  783. package/dist/types/TenantContainer.d.ts +21 -13
  784. package/dist/types/TenantContainer.d.ts.map +1 -1
  785. package/dist/types/bridges/system/IdentityFetcher.d.ts +2 -2
  786. package/dist/types/bridges/system/IdentityFetcher.d.ts.map +1 -1
  787. package/dist/types/exceptions.d.ts.map +1 -1
  788. package/dist/types/migrations/2026-06-18-120000-idp-claim-mapping.d.ts +3 -0
  789. package/dist/types/migrations/2026-06-18-120000-idp-claim-mapping.d.ts.map +1 -0
  790. package/dist/types/migrations/2026-08-03-120000-person-enable-auth-log.d.ts +3 -0
  791. package/dist/types/migrations/2026-08-03-120000-person-enable-auth-log.d.ts.map +1 -0
  792. package/dist/types/migrations/2026-08-04-120000-config-panel.d.ts +3 -0
  793. package/dist/types/migrations/2026-08-04-120000-config-panel.d.ts.map +1 -0
  794. package/dist/types/migrations/runner.d.ts.map +1 -1
  795. package/dist/types/migrations/snapshot-factory.d.ts.map +1 -1
  796. package/dist/types/migrations/snapshot.d.ts.map +1 -1
  797. package/dist/types/migrations/tenantCredentials.d.ts.map +1 -1
  798. package/dist/types/model/authorization/AclSchemaAccessNodeFactory.d.ts.map +1 -1
  799. package/dist/types/model/authorization/DirectPermissionsAccessNode.d.ts.map +1 -1
  800. package/dist/types/model/authorization/Identity.d.ts.map +1 -1
  801. package/dist/types/model/authorization/IdentityFactory.d.ts.map +1 -1
  802. package/dist/types/model/authorization/IdentityScope.d.ts.map +1 -1
  803. package/dist/types/model/authorization/MembershipMatcher.d.ts.map +1 -1
  804. package/dist/types/model/authorization/PermissionActions.d.ts.map +1 -1
  805. package/dist/types/model/authorization/PermissionContext.d.ts.map +1 -1
  806. package/dist/types/model/authorization/PermissionContextFactory.d.ts.map +1 -1
  807. package/dist/types/model/authorization/PermissionsFactory.d.ts.map +1 -1
  808. package/dist/types/model/authorization/ProjectScope.d.ts.map +1 -1
  809. package/dist/types/model/authorization/ProjectScopeFactory.d.ts.map +1 -1
  810. package/dist/types/model/commands/CommandBus.d.ts.map +1 -1
  811. package/dist/types/model/commands/apiKey/ApiKeyHelper.d.ts.map +1 -1
  812. package/dist/types/model/commands/apiKey/CreateApiKeyCommand.d.ts.map +1 -1
  813. package/dist/types/model/commands/apiKey/DisableApiKeyCommand.d.ts.map +1 -1
  814. package/dist/types/model/commands/apiKey/DisableIdentityApiKeysCommand.d.ts.map +1 -1
  815. package/dist/types/model/commands/apiKey/DisableOneOffApiKeyCommand.d.ts.map +1 -1
  816. package/dist/types/model/commands/apiKey/ProlongApiKeyCommand.d.ts +1 -1
  817. package/dist/types/model/commands/apiKey/ProlongApiKeyCommand.d.ts.map +1 -1
  818. package/dist/types/model/commands/authLog/CreateAuthLogEntryCommand.d.ts.map +1 -1
  819. package/dist/types/model/commands/authPolicy/CreateAuthPolicyCommand.d.ts.map +1 -1
  820. package/dist/types/model/commands/authPolicy/DeleteAuthPolicyCommand.d.ts.map +1 -1
  821. package/dist/types/model/commands/authPolicy/UpdateAuthPolicyCommand.d.ts.map +1 -1
  822. package/dist/types/model/commands/backupCode/ConsumeBackupCodeCommand.d.ts.map +1 -1
  823. package/dist/types/model/commands/backupCode/CreateBackupCodeCommand.d.ts.map +1 -1
  824. package/dist/types/model/commands/backupCode/DeleteBackupCodesCommand.d.ts.map +1 -1
  825. package/dist/types/model/commands/configuration/UpdateConfigurationCommand.d.ts.map +1 -1
  826. package/dist/types/model/commands/identity/CreateIdentityCommand.d.ts.map +1 -1
  827. package/dist/types/model/commands/identity/PatchIdentityGlobalRoles.d.ts.map +1 -1
  828. package/dist/types/model/commands/idp/ClaimIdpRevalidationCommand.d.ts.map +1 -1
  829. package/dist/types/model/commands/idp/CreateIdpCommand.d.ts.map +1 -1
  830. package/dist/types/model/commands/idp/CreateIdpSessionCommand.d.ts.map +1 -1
  831. package/dist/types/model/commands/idp/DisableIdpCommand.d.ts.map +1 -1
  832. package/dist/types/model/commands/idp/DisconnectPersonIdentityProviderCommand.d.ts.map +1 -1
  833. package/dist/types/model/commands/idp/EnableIdpCommand.d.ts.map +1 -1
  834. package/dist/types/model/commands/idp/UpdateIdpCommand.d.ts.map +1 -1
  835. package/dist/types/model/commands/idp/UpdateIdpSessionCommand.d.ts.map +1 -1
  836. package/dist/types/model/commands/mailTemplate/AddMailTemplateCommand.d.ts.map +1 -1
  837. package/dist/types/model/commands/mailTemplate/RemoveMailTemplateCommand.d.ts.map +1 -1
  838. package/dist/types/model/commands/membership/AddProjectMemberCommand.d.ts.map +1 -1
  839. package/dist/types/model/commands/membership/CreateOrUpdateProjectMembershipCommand.d.ts.map +1 -1
  840. package/dist/types/model/commands/membership/RemoveProjectMemberCommand.d.ts.map +1 -1
  841. package/dist/types/model/commands/membership/{RemoveProjectMembershipsCommand.d.ts → RemoveProjectMembershipCommand.d.ts} +1 -1
  842. package/dist/types/model/commands/membership/RemoveProjectMembershipCommand.d.ts.map +1 -0
  843. package/dist/types/model/commands/membership/UpdateProjectMemberCommand.d.ts.map +1 -1
  844. package/dist/types/model/commands/membership/index.d.ts +2 -1
  845. package/dist/types/model/commands/membership/index.d.ts.map +1 -1
  846. package/dist/types/model/commands/membership/variables/PatchProjectMembershipVariableValuesCommand.d.ts.map +1 -1
  847. package/dist/types/model/commands/membership/variables/PatchProjectMembershipVariablesCommand.d.ts.map +1 -1
  848. package/dist/types/model/commands/membership/variables/SetProjectMembershipVariableValuesCommand.d.ts.map +1 -1
  849. package/dist/types/model/commands/membership/variables/index.d.ts +1 -0
  850. package/dist/types/model/commands/membership/variables/index.d.ts.map +1 -1
  851. package/dist/types/model/commands/otp/ConfirmOtpCommand.d.ts.map +1 -1
  852. package/dist/types/model/commands/otp/DisableOtpCommand.d.ts.map +1 -1
  853. package/dist/types/model/commands/otp/PrepareOtpCommand.d.ts.map +1 -1
  854. package/dist/types/model/commands/otp/ReEncryptOtpSecretCommand.d.ts.map +1 -1
  855. package/dist/types/model/commands/otp/SetEmailOtpEnabledCommand.d.ts.map +1 -1
  856. package/dist/types/model/commands/person/ChangePasswordCommand.d.ts.map +1 -1
  857. package/dist/types/model/commands/person/ChangeProfileCommand.d.ts.map +1 -1
  858. package/dist/types/model/commands/person/CreatePersonCommand.d.ts.map +1 -1
  859. package/dist/types/model/commands/person/CreatePersonIdentityProviderIdentifierCommand.d.ts.map +1 -1
  860. package/dist/types/model/commands/person/DisablePersonCommand.d.ts.map +1 -1
  861. package/dist/types/model/commands/person/EnablePersonCommand.d.ts +7 -0
  862. package/dist/types/model/commands/person/EnablePersonCommand.d.ts.map +1 -0
  863. package/dist/types/model/commands/person/MarkEmailVerifiedCommand.d.ts.map +1 -1
  864. package/dist/types/model/commands/person/ResetPersonMfaCommand.d.ts.map +1 -1
  865. package/dist/types/model/commands/person/SetMfaGraceUntilCommand.d.ts.map +1 -1
  866. package/dist/types/model/commands/person/TogglePersonPasswordlessCommand.d.ts.map +1 -1
  867. package/dist/types/model/commands/personToken/ActivateOtpCommand.d.ts.map +1 -1
  868. package/dist/types/model/commands/personToken/ClaimOtpAttemptCommand.d.ts.map +1 -1
  869. package/dist/types/model/commands/personToken/CreatePersonTokenCommand.d.ts.map +1 -1
  870. package/dist/types/model/commands/personToken/IncreaseOtpAttemptCommand.d.ts.map +1 -1
  871. package/dist/types/model/commands/personToken/InvalidateEmailOtpTokensCommand.d.ts.map +1 -1
  872. package/dist/types/model/commands/personToken/InvalidateTokenCommand.d.ts.map +1 -1
  873. package/dist/types/model/commands/personToken/ResetPasswordCommand.d.ts.map +1 -1
  874. package/dist/types/model/commands/personToken/SaveEmailOtpTokenCommand.d.ts.map +1 -1
  875. package/dist/types/model/commands/personToken/SavePersonTokenCommand.d.ts.map +1 -1
  876. package/dist/types/model/commands/project/CreateProjectCommand.d.ts.map +1 -1
  877. package/dist/types/model/commands/project/SetProjectSecretCommand.d.ts.map +1 -1
  878. package/dist/types/model/commands/project/UpdateProjectCommand.d.ts.map +1 -1
  879. package/dist/types/model/commands/rateLimit/RecordRateLimitEventCommand.d.ts.map +1 -1
  880. package/dist/types/model/dtos/Password.d.ts.map +1 -1
  881. package/dist/types/model/mailing/UserMailer.d.ts.map +1 -1
  882. package/dist/types/model/mailing/templates/BackupCodesExhausted.mustache.d.ts.map +1 -1
  883. package/dist/types/model/mailing/templates/EmailChangeNotify.mustache.d.ts.map +1 -1
  884. package/dist/types/model/mailing/templates/EmailChangeVerify.mustache.d.ts.map +1 -1
  885. package/dist/types/model/mailing/templates/EmailOtp.mustache.d.ts.map +1 -1
  886. package/dist/types/model/mailing/templates/EmailVerification.mustache.d.ts.map +1 -1
  887. package/dist/types/model/mailing/templates/ExistingUserInvited.mustache.d.ts.map +1 -1
  888. package/dist/types/model/mailing/templates/ForcedSignOut.mustache.d.ts.map +1 -1
  889. package/dist/types/model/mailing/templates/Layout.mustache.d.ts.map +1 -1
  890. package/dist/types/model/mailing/templates/NewUserInvited.mustache.d.ts.map +1 -1
  891. package/dist/types/model/mailing/templates/PasswordReset.mustache.d.ts.map +1 -1
  892. package/dist/types/model/mailing/templates/PasswordlessSignIn.mustache.d.ts.map +1 -1
  893. package/dist/types/model/mailing/templates/UnusualLogin.mustache.d.ts.map +1 -1
  894. package/dist/types/model/mailing/type.d.ts.map +1 -1
  895. package/dist/types/model/queries/apiKey/ApiKeyListQuery.d.ts.map +1 -1
  896. package/dist/types/model/queries/apiKey/ApiKeyQuery.d.ts.map +1 -1
  897. package/dist/types/model/queries/apiKey/ApiKeySessionsQuery.d.ts.map +1 -1
  898. package/dist/types/model/queries/authLog/AuthLogQuery.d.ts.map +1 -1
  899. package/dist/types/model/queries/authLog/NextLoginAttemptQuery.d.ts.map +1 -1
  900. package/dist/types/model/queries/authLog/NextMailAttemptQuery.d.ts.map +1 -1
  901. package/dist/types/model/queries/authPolicy/AuthPoliciesQuery.d.ts.map +1 -1
  902. package/dist/types/model/queries/configuration/ConfigurationQuery.d.ts.map +1 -1
  903. package/dist/types/model/queries/identity/IdentityQuery.d.ts.map +1 -1
  904. package/dist/types/model/queries/idp/IdentityProviderBySlugQuery.d.ts.map +1 -1
  905. package/dist/types/model/queries/idp/IdentityProvidersQuery.d.ts.map +1 -1
  906. package/dist/types/model/queries/idp/IdpSessionByApiKeyQuery.d.ts.map +1 -1
  907. package/dist/types/model/queries/idp/IdpSessionsBySidQuery.d.ts.map +1 -1
  908. package/dist/types/model/queries/idp/IdpSessionsBySubQuery.d.ts.map +1 -1
  909. package/dist/types/model/queries/idp/PersonIdentityProvidersQuery.d.ts.map +1 -1
  910. package/dist/types/model/queries/idp/helpers.d.ts.map +1 -1
  911. package/dist/types/model/queries/mailTemplate/MailTemplateListQuery.d.ts.map +1 -1
  912. package/dist/types/model/queries/mailTemplate/MailTemplateQuery.d.ts.map +1 -1
  913. package/dist/types/model/queries/membership/AllProjectRolesByIdentityQuery.d.ts.map +1 -1
  914. package/dist/types/model/queries/membership/ProjectMembersQuery.d.ts.map +1 -1
  915. package/dist/types/model/queries/membership/ProjectMembershipByIdentityQuery.d.ts.map +1 -1
  916. package/dist/types/model/queries/membership/ProjectRolesByIdentityQuery.d.ts.map +1 -1
  917. package/dist/types/model/queries/membership/ProjectSlugSpecification.d.ts.map +1 -1
  918. package/dist/types/model/queries/person/PersonByIdPQuery.d.ts.map +1 -1
  919. package/dist/types/model/queries/person/PersonByIdentityBatchQuery.d.ts.map +1 -1
  920. package/dist/types/model/queries/person/PersonQuery.d.ts.map +1 -1
  921. package/dist/types/model/queries/person/PersonQueryBuilderFactory.d.ts.map +1 -1
  922. package/dist/types/model/queries/person/PersonsQuery.d.ts.map +1 -1
  923. package/dist/types/model/queries/person/types.d.ts +1 -0
  924. package/dist/types/model/queries/person/types.d.ts.map +1 -1
  925. package/dist/types/model/queries/personToken/PersonTokenQuery.d.ts.map +1 -1
  926. package/dist/types/model/queries/project/ProjectBySlugQuery.d.ts.map +1 -1
  927. package/dist/types/model/queries/project/ProjectSecretKeysQuery.d.ts.map +1 -1
  928. package/dist/types/model/queries/project/ProjectSecretsQuery.d.ts.map +1 -1
  929. package/dist/types/model/queries/project/ProjectUpdateTimestampQuery.d.ts.map +1 -1
  930. package/dist/types/model/queries/project/ProjectsByIdentityQuery.d.ts.map +1 -1
  931. package/dist/types/model/queries/project/ProjectsQuery.d.ts.map +1 -1
  932. package/dist/types/model/queries/rateLimit/RateLimitCountQuery.d.ts.map +1 -1
  933. package/dist/types/model/service/AuthLogService.d.ts.map +1 -1
  934. package/dist/types/model/service/AuthPolicyManager.d.ts.map +1 -1
  935. package/dist/types/model/service/AuthPolicyResolver.d.ts.map +1 -1
  936. package/dist/types/model/service/BackupCodeManager.d.ts.map +1 -1
  937. package/dist/types/model/service/ConfigurationManager.d.ts.map +1 -1
  938. package/dist/types/model/service/EmailChangeManager.d.ts.map +1 -1
  939. package/dist/types/model/service/EmailOtpManager.d.ts.map +1 -1
  940. package/dist/types/model/service/EmailValidator.d.ts.map +1 -1
  941. package/dist/types/model/service/EmailVerificationManager.d.ts.map +1 -1
  942. package/dist/types/model/service/HibpChecker.d.ts.map +1 -1
  943. package/dist/types/model/service/IDPSignInManager.d.ts +11 -1
  944. package/dist/types/model/service/IDPSignInManager.d.ts.map +1 -1
  945. package/dist/types/model/service/InviteManager.d.ts.map +1 -1
  946. package/dist/types/model/service/LoginRiskAnalyzer.d.ts +1 -1
  947. package/dist/types/model/service/LoginRiskAnalyzer.d.ts.map +1 -1
  948. package/dist/types/model/service/MailTemplateManager.d.ts.map +1 -1
  949. package/dist/types/model/service/MembershipValidator.d.ts.map +1 -1
  950. package/dist/types/model/service/OtpAuthenticator.d.ts.map +1 -1
  951. package/dist/types/model/service/OtpManager.d.ts.map +1 -1
  952. package/dist/types/model/service/PanelAccessResolver.d.ts +19 -0
  953. package/dist/types/model/service/PanelAccessResolver.d.ts.map +1 -0
  954. package/dist/types/model/service/PasswordChangeManager.d.ts.map +1 -1
  955. package/dist/types/model/service/PasswordResetManager.d.ts.map +1 -1
  956. package/dist/types/model/service/PasswordStrengthValidator.d.ts.map +1 -1
  957. package/dist/types/model/service/PasswordlessSignInManager.d.ts.map +1 -1
  958. package/dist/types/model/service/PersonAccessManager.d.ts +5 -2
  959. package/dist/types/model/service/PersonAccessManager.d.ts.map +1 -1
  960. package/dist/types/model/service/PersonManager.d.ts.map +1 -1
  961. package/dist/types/model/service/ProjectManager.d.ts.map +1 -1
  962. package/dist/types/model/service/ProjectMemberManager.d.ts.map +1 -1
  963. package/dist/types/model/service/RateLimiter.d.ts.map +1 -1
  964. package/dist/types/model/service/RolesManager.d.ts.map +1 -1
  965. package/dist/types/model/service/SecretsManager.d.ts.map +1 -1
  966. package/dist/types/model/service/SignInManager.d.ts.map +1 -1
  967. package/dist/types/model/service/SignOutManager.d.ts.map +1 -1
  968. package/dist/types/model/service/SignUpManager.d.ts.map +1 -1
  969. package/dist/types/model/service/apiKey/ApiKeyManager.d.ts.map +1 -1
  970. package/dist/types/model/service/apiKey/ApiKeyService.d.ts.map +1 -1
  971. package/dist/types/model/service/apiKey/UnpersistedApiKeyManager.d.ts +18 -0
  972. package/dist/types/model/service/apiKey/UnpersistedApiKeyManager.d.ts.map +1 -1
  973. package/dist/types/model/service/captcha/CaptchaValidator.d.ts.map +1 -1
  974. package/dist/types/model/service/captcha/HCaptchaProvider.d.ts.map +1 -1
  975. package/dist/types/model/service/captcha/RecaptchaV3Provider.d.ts.map +1 -1
  976. package/dist/types/model/service/captcha/TurnstileProvider.d.ts.map +1 -1
  977. package/dist/types/model/service/helpers/getPreferredProject.d.ts.map +1 -1
  978. package/dist/types/model/service/helpers/isPasswordlessEnabled.d.ts.map +1 -1
  979. package/dist/types/model/service/idp/BackchannelLogoutManager.d.ts.map +1 -1
  980. package/dist/types/model/service/idp/ClaimMapping.d.ts +330 -0
  981. package/dist/types/model/service/idp/ClaimMapping.d.ts.map +1 -0
  982. package/dist/types/model/service/idp/ClaimMappingEvaluator.d.ts +30 -0
  983. package/dist/types/model/service/idp/ClaimMappingEvaluator.d.ts.map +1 -0
  984. package/dist/types/model/service/idp/ClaimMappingValidation.d.ts +55 -0
  985. package/dist/types/model/service/idp/ClaimMappingValidation.d.ts.map +1 -0
  986. package/dist/types/model/service/idp/IDPClaimSyncService.d.ts +113 -0
  987. package/dist/types/model/service/idp/IDPClaimSyncService.d.ts.map +1 -0
  988. package/dist/types/model/service/idp/IDPHandlerRegistry.d.ts.map +1 -1
  989. package/dist/types/model/service/idp/IDPManager.d.ts +31 -1
  990. package/dist/types/model/service/idp/IDPManager.d.ts.map +1 -1
  991. package/dist/types/model/service/idp/IdentityProviderHandler.d.ts +7 -0
  992. package/dist/types/model/service/idp/IdentityProviderHandler.d.ts.map +1 -1
  993. package/dist/types/model/service/idp/IdpSessionRevalidator.d.ts +13 -1
  994. package/dist/types/model/service/idp/IdpSessionRevalidator.d.ts.map +1 -1
  995. package/dist/types/model/service/idp/PersonIdentityProviderManager.d.ts.map +1 -1
  996. package/dist/types/model/service/idp/index.d.ts +4 -0
  997. package/dist/types/model/service/idp/index.d.ts.map +1 -1
  998. package/dist/types/model/service/idp/providers/AppleProvider.d.ts +2 -2
  999. package/dist/types/model/service/idp/providers/AppleProvider.d.ts.map +1 -1
  1000. package/dist/types/model/service/idp/providers/FacebookProvider.d.ts +2 -2
  1001. package/dist/types/model/service/idp/providers/FacebookProvider.d.ts.map +1 -1
  1002. package/dist/types/model/service/idp/providers/OIDCHelpers.d.ts +13 -1
  1003. package/dist/types/model/service/idp/providers/OIDCHelpers.d.ts.map +1 -1
  1004. package/dist/types/model/service/idp/providers/OIDCProvider.d.ts +1 -1
  1005. package/dist/types/model/service/idp/providers/OIDCProvider.d.ts.map +1 -1
  1006. package/dist/types/model/service/idp/providers/OIDCTypes.d.ts +5 -5
  1007. package/dist/types/model/service/idp/providers/helpers.d.ts.map +1 -1
  1008. package/dist/types/model/service/index.d.ts +1 -0
  1009. package/dist/types/model/service/index.d.ts.map +1 -1
  1010. package/dist/types/model/service/membershipUtils.d.ts.map +1 -1
  1011. package/dist/types/model/type/AuthLog.d.ts +1 -1
  1012. package/dist/types/model/type/AuthLog.d.ts.map +1 -1
  1013. package/dist/types/model/type/Config.d.ts +2 -0
  1014. package/dist/types/model/type/Config.d.ts.map +1 -1
  1015. package/dist/types/model/type/RateLimit.d.ts +6 -6
  1016. package/dist/types/model/type/RateLimit.d.ts.map +1 -1
  1017. package/dist/types/model/utils/DatabaseContext.d.ts +14 -1
  1018. package/dist/types/model/utils/DatabaseContext.d.ts.map +1 -1
  1019. package/dist/types/model/utils/Response.d.ts.map +1 -1
  1020. package/dist/types/model/utils/email.d.ts.map +1 -1
  1021. package/dist/types/model/utils/hex.d.ts.map +1 -1
  1022. package/dist/types/model/utils/interval.d.ts.map +1 -1
  1023. package/dist/types/model/utils/time.d.ts.map +1 -1
  1024. package/dist/types/model/utils/token.d.ts.map +1 -1
  1025. package/dist/types/resolvers/ResolverFactory.d.ts +2 -0
  1026. package/dist/types/resolvers/ResolverFactory.d.ts.map +1 -1
  1027. package/dist/types/resolvers/TenantResolverContextFactory.d.ts.map +1 -1
  1028. package/dist/types/resolvers/errorUtils.d.ts.map +1 -1
  1029. package/dist/types/resolvers/membershipUtils.d.ts.map +1 -1
  1030. package/dist/types/resolvers/mutation/apiKey/CreateApiKeyMutationResolver.d.ts.map +1 -1
  1031. package/dist/types/resolvers/mutation/apiKey/DisableApiKeyMutationResolver.d.ts.map +1 -1
  1032. package/dist/types/resolvers/mutation/configuration/AuthPolicyMutationResolver.d.ts.map +1 -1
  1033. package/dist/types/resolvers/mutation/configuration/ConfigurationMutationResolver.d.ts.map +1 -1
  1034. package/dist/types/resolvers/mutation/identity/GlobalRolesMutationResolver.d.ts.map +1 -1
  1035. package/dist/types/resolvers/mutation/idp/AddIDPMutationResolver.d.ts.map +1 -1
  1036. package/dist/types/resolvers/mutation/idp/DisableIDPMutationResolver.d.ts.map +1 -1
  1037. package/dist/types/resolvers/mutation/idp/DisconnectMyIdentityProviderMutationResolver.d.ts.map +1 -1
  1038. package/dist/types/resolvers/mutation/idp/EnableIDPMutationResolver.d.ts.map +1 -1
  1039. package/dist/types/resolvers/mutation/idp/UpdateIDPMutationResolver.d.ts.map +1 -1
  1040. package/dist/types/resolvers/mutation/idp/audit.d.ts.map +1 -1
  1041. package/dist/types/resolvers/mutation/mailTemplates/MailTemplateMutationResolver.d.ts.map +1 -1
  1042. package/dist/types/resolvers/mutation/person/ChangePasswordMutationResolver.d.ts.map +1 -1
  1043. package/dist/types/resolvers/mutation/person/ChangeProfileMutationResolver.d.ts.map +1 -1
  1044. package/dist/types/resolvers/mutation/person/DisablePersonMutationResolver.d.ts +1 -1
  1045. package/dist/types/resolvers/mutation/person/DisablePersonMutationResolver.d.ts.map +1 -1
  1046. package/dist/types/resolvers/mutation/person/EmailOtpMutationResolver.d.ts.map +1 -1
  1047. package/dist/types/resolvers/mutation/person/EmailVerificationMutationResolver.d.ts.map +1 -1
  1048. package/dist/types/resolvers/mutation/person/EnablePersonMutationResolver.d.ts +11 -0
  1049. package/dist/types/resolvers/mutation/person/EnablePersonMutationResolver.d.ts.map +1 -0
  1050. package/dist/types/resolvers/mutation/person/ForceSignOutMutationResolver.d.ts.map +1 -1
  1051. package/dist/types/resolvers/mutation/person/IDPMutationResolver.d.ts.map +1 -1
  1052. package/dist/types/resolvers/mutation/person/InviteMutationResolver.d.ts.map +1 -1
  1053. package/dist/types/resolvers/mutation/person/OtpMutationResolver.d.ts.map +1 -1
  1054. package/dist/types/resolvers/mutation/person/PasswordlessMutationResolver.d.ts.map +1 -1
  1055. package/dist/types/resolvers/mutation/person/RegenerateBackupCodesMutationResolver.d.ts.map +1 -1
  1056. package/dist/types/resolvers/mutation/person/ResetPasswordMutationResolver.d.ts.map +1 -1
  1057. package/dist/types/resolvers/mutation/person/ResetPersonMfaMutationResolver.d.ts.map +1 -1
  1058. package/dist/types/resolvers/mutation/person/RevokeSessionMutationResolver.d.ts.map +1 -1
  1059. package/dist/types/resolvers/mutation/person/SignInMutationResolver.d.ts.map +1 -1
  1060. package/dist/types/resolvers/mutation/person/SignOutMutationResolver.d.ts.map +1 -1
  1061. package/dist/types/resolvers/mutation/person/SignUpMutationResolver.d.ts.map +1 -1
  1062. package/dist/types/resolvers/mutation/person/TogglePasswordlessMutationResolver.d.ts.map +1 -1
  1063. package/dist/types/resolvers/mutation/project/CreateProjectMutationResolver.d.ts.map +1 -1
  1064. package/dist/types/resolvers/mutation/project/SetProjectSecretMutationResolver.d.ts.map +1 -1
  1065. package/dist/types/resolvers/mutation/project/UpdateProjectMutationResolver.d.ts.map +1 -1
  1066. package/dist/types/resolvers/mutation/projectMember/AddProjectMemberMutationResolver.d.ts.map +1 -1
  1067. package/dist/types/resolvers/mutation/projectMember/RemoveProjectMemberMutationResolver.d.ts.map +1 -1
  1068. package/dist/types/resolvers/mutation/projectMember/UpdateProjectMemberMutationResolver.d.ts.map +1 -1
  1069. package/dist/types/resolvers/mutation/projectMember/audit.d.ts +1 -1
  1070. package/dist/types/resolvers/mutation/projectMember/audit.d.ts.map +1 -1
  1071. package/dist/types/resolvers/query/ApiKeyQueryResolver.d.ts.map +1 -1
  1072. package/dist/types/resolvers/query/AuthLogQueryResolver.d.ts.map +1 -1
  1073. package/dist/types/resolvers/query/AuthPolicyQueryResolver.d.ts.map +1 -1
  1074. package/dist/types/resolvers/query/ConfigurationQueryResolver.d.ts.map +1 -1
  1075. package/dist/types/resolvers/query/IDPQueryResolver.d.ts.map +1 -1
  1076. package/dist/types/resolvers/query/MailTemplateQueryResolver.d.ts.map +1 -1
  1077. package/dist/types/resolvers/query/MeQueryResolver.d.ts.map +1 -1
  1078. package/dist/types/resolvers/query/PersonQueryResolver.d.ts.map +1 -1
  1079. package/dist/types/resolvers/query/ProjectMembersQueryResolver.d.ts.map +1 -1
  1080. package/dist/types/resolvers/query/ProjectQueryResolver.d.ts.map +1 -1
  1081. package/dist/types/resolvers/responseHelpers/ApiKeyResponseFactory.d.ts.map +1 -1
  1082. package/dist/types/resolvers/responseHelpers/PersonResponseFactory.d.ts.map +1 -1
  1083. package/dist/types/resolvers/responseHelpers/ProjectResponseFactory.d.ts +10 -0
  1084. package/dist/types/resolvers/responseHelpers/ProjectResponseFactory.d.ts.map +1 -0
  1085. package/dist/types/resolvers/responseHelpers/SignInResponseFactory.d.ts.map +1 -1
  1086. package/dist/types/resolvers/types/IdentityTypeResolver.d.ts.map +1 -1
  1087. package/dist/types/resolvers/types/PersonTypeResolver.d.ts +15 -1
  1088. package/dist/types/resolvers/types/PersonTypeResolver.d.ts.map +1 -1
  1089. package/dist/types/resolvers/types/ProjectTypeResolver.d.ts +15 -6
  1090. package/dist/types/resolvers/types/ProjectTypeResolver.d.ts.map +1 -1
  1091. package/dist/types/schema/index.d.ts +161 -0
  1092. package/dist/types/schema/index.d.ts.map +1 -1
  1093. package/dist/types/schema/tenant.graphql.d.ts.map +1 -1
  1094. package/dist/types/schema/types.d.ts +2 -2
  1095. package/dist/types/schema/types.d.ts.map +1 -1
  1096. package/dist/types/tsconfig.tsbuildinfo +1 -1
  1097. package/dist/types/utils/Mailer.d.ts.map +1 -1
  1098. package/dist/types/utils/TemplateRenderer.d.ts.map +1 -1
  1099. package/dist/types/utils/array.d.ts.map +1 -1
  1100. package/dist/types/utils/batchQuery.d.ts.map +1 -1
  1101. package/package.json +12 -12
  1102. package/src/TenantContainer.ts +17 -3
  1103. package/src/migrations/2026-06-18-120000-idp-claim-mapping.ts +15 -0
  1104. package/src/migrations/2026-08-03-120000-person-enable-auth-log.ts +12 -0
  1105. package/src/migrations/2026-08-04-120000-config-panel.ts +13 -0
  1106. package/src/migrations/runner.ts +6 -0
  1107. package/src/migrations/snapshot.ts +6 -1
  1108. package/src/model/commands/configuration/UpdateConfigurationCommand.ts +5 -4
  1109. package/src/model/commands/membership/UpdateProjectMemberCommand.ts +1 -1
  1110. package/src/model/commands/membership/index.ts +2 -1
  1111. package/src/model/commands/membership/variables/index.ts +1 -0
  1112. package/src/model/commands/person/EnablePersonCommand.ts +18 -0
  1113. package/src/model/queries/configuration/ConfigurationQuery.ts +4 -0
  1114. package/src/model/queries/membership/ProjectMembersQuery.ts +1 -0
  1115. package/src/model/queries/person/PersonQueryBuilderFactory.ts +1 -0
  1116. package/src/model/queries/person/types.ts +1 -0
  1117. package/src/model/service/AuthLogService.ts +18 -2
  1118. package/src/model/service/IDPSignInManager.ts +49 -1
  1119. package/src/model/service/PanelAccessResolver.ts +32 -0
  1120. package/src/model/service/PersonAccessManager.ts +19 -3
  1121. package/src/model/service/apiKey/ApiKeyManager.ts +5 -3
  1122. package/src/model/service/apiKey/UnpersistedApiKeyManager.ts +24 -0
  1123. package/src/model/service/idp/ClaimMapping.ts +283 -0
  1124. package/src/model/service/idp/ClaimMappingEvaluator.ts +226 -0
  1125. package/src/model/service/idp/ClaimMappingValidation.ts +158 -0
  1126. package/src/model/service/idp/IDPClaimSyncService.ts +401 -0
  1127. package/src/model/service/idp/IDPManager.ts +126 -21
  1128. package/src/model/service/idp/IdentityProviderHandler.ts +7 -0
  1129. package/src/model/service/idp/IdpSessionRevalidator.ts +90 -0
  1130. package/src/model/service/idp/index.ts +4 -0
  1131. package/src/model/service/idp/providers/OIDCHelpers.ts +161 -53
  1132. package/src/model/service/idp/providers/OIDCProvider.ts +4 -1
  1133. package/src/model/service/index.ts +1 -0
  1134. package/src/model/type/AuthLog.ts +3 -0
  1135. package/src/model/type/Config.ts +3 -0
  1136. package/src/model/utils/DatabaseContext.ts +27 -6
  1137. package/src/resolvers/ResolverFactory.ts +6 -0
  1138. package/src/resolvers/mutation/person/DisablePersonMutationResolver.ts +3 -3
  1139. package/src/resolvers/mutation/person/EnablePersonMutationResolver.ts +50 -0
  1140. package/src/resolvers/mutation/person/IDPMutationResolver.ts +31 -0
  1141. package/src/resolvers/query/ProjectQueryResolver.ts +3 -2
  1142. package/src/resolvers/responseHelpers/PersonResponseFactory.ts +5 -0
  1143. package/src/resolvers/responseHelpers/ProjectResponseFactory.ts +24 -0
  1144. package/src/resolvers/types/IdentityTypeResolver.ts +39 -3
  1145. package/src/resolvers/types/PersonTypeResolver.ts +35 -2
  1146. package/src/resolvers/types/ProjectTypeResolver.ts +33 -1
  1147. package/src/schema/index.ts +183 -0
  1148. package/src/schema/tenant.graphql.ts +116 -0
  1149. package/tests/cases/integration/mocked/configurationPanel.test.ts +105 -0
  1150. package/tests/cases/integration/mocked/disablePersonMutation.test.ts +89 -0
  1151. package/tests/cases/integration/mocked/enablePersonMutation.test.ts +130 -0
  1152. package/tests/cases/integration/mocked/idpClaimMappingConfig.test.ts +332 -0
  1153. package/tests/cases/integration/mocked/listProjectMembersQuery.test.ts +8 -3
  1154. package/tests/cases/integration/mocked/permissionsQuery.test.ts +153 -0
  1155. package/tests/cases/integration/mocked/personsQuery.test.ts +38 -5
  1156. package/tests/cases/integration/mocked/signInIdpClaimMapping.test.ts +1244 -0
  1157. package/tests/cases/integration/mocked/signInIdpClaimMappingFixes.test.ts +340 -0
  1158. package/tests/cases/integration/mocked/signInIdpClaimMappingSafety.test.ts +525 -0
  1159. package/tests/cases/integration/mocked/sql/getConfigSql.ts +3 -0
  1160. package/tests/cases/integration/mocked/sql/getProjectBySlugSql.ts +1 -1
  1161. package/tests/cases/integration/mocked/sql/listPersonsSql.ts +5 -2
  1162. package/tests/cases/integration/mocked/sql/removeMembershipSql.ts +14 -0
  1163. package/tests/cases/unit/databaseContextRetry.test.ts +81 -0
  1164. package/tests/cases/unit/idp/claimMappingEvaluator.test.ts +554 -0
  1165. package/tests/cases/unit/idp/claimMappingValidation.test.ts +134 -0
  1166. package/tests/cases/unit/idp/idpManagerConfigMerge.test.ts +97 -0
  1167. package/tests/cases/unit/idp/idpManagerUnknownConfigKeys.test.ts +101 -0
  1168. package/tests/cases/unit/idp/idpSessionRevalidator.test.ts +226 -24
  1169. package/tests/cases/unit/idp/oidcClaims.test.ts +29 -0
  1170. package/tests/cases/unit/idp/oidcResponse.test.ts +54 -0
  1171. package/tests/cases/unit/idp/oidcRevalidate.test.ts +94 -2
  1172. package/tests/cases/unit/panelAccessResolver.test.ts +57 -0
  1173. package/tests/cases/unit/updateConfigurationCommand.test.ts +63 -0
  1174. package/tests/src/IdPMock.ts +4 -0
  1175. package/tests/src/testTenant.ts +32 -1
  1176. package/dist/development/src/model/commands/membership/RemoveProjectMembershipsCommand.cjs.map +0 -1
  1177. package/dist/development/src/model/commands/membership/RemoveProjectMembershipsCommand.js.map +0 -1
  1178. package/dist/production/src/model/commands/membership/RemoveProjectMembershipsCommand.cjs.map +0 -1
  1179. package/dist/production/src/model/commands/membership/RemoveProjectMembershipsCommand.js.map +0 -1
  1180. package/dist/types/model/commands/membership/RemoveProjectMembershipsCommand.d.ts.map +0 -1
  1181. /package/src/model/commands/membership/{RemoveProjectMembershipsCommand.ts → RemoveProjectMembershipCommand.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"IdpSessionRevalidator.cjs","sources":["../../../../../../../packages/engine-tenant-api/src/model/service/idp/IdpSessionRevalidator.ts"],"sourcesContent":["import { DatabaseContext } from '../../utils/index.js'\nimport { ApiKeyRequestInfo } from '../../commands/index.js'\nimport { ApiKeyRow } from '../../queries/apiKey/ApiKeyQuery.js'\nimport { IdpSessionByApiKeyQuery, IdpSessionRow } from '../../queries/idp/IdpSessionByApiKeyQuery.js'\nimport { IDPHandlerRegistry } from './IDPHandlerRegistry.js'\nimport { ClaimIdpRevalidationCommand } from '../../commands/idp/ClaimIdpRevalidationCommand.js'\nimport { UpdateIdpSessionCommand } from '../../commands/idp/UpdateIdpSessionCommand.js'\nimport { DisableApiKeyCommand } from '../../commands/index.js'\nimport { CreateAuthLogEntryCommand } from '../../commands/authLog/CreateAuthLogEntryCommand.js'\nimport { REVALIDATION_DEFAULT_FALLBACK_INTERVAL, REVALIDATION_DEFAULT_MIN_INTERVAL, REVALIDATION_DEFAULT_SOFT_THRESHOLD } from './IDPRevalidation.js'\nimport { IdentityProviderHandler, RevalidationResult } from './IdentityProviderHandler.js'\n\nexport type RevalidationOutcome = 'valid' | 'revoked'\n\ntype ResolvedRevalidationConfig = {\n\tenabled: boolean\n\tsoftThreshold: number\n\tminInterval: string\n\tfallbackInterval: string\n\tmode: 'auto' | 'blocking'\n}\n\n/**\n * Decision for the current request: whether to attempt a revalidation, and if so whether it\n * must block the request. `claimInterval` is the single-flight floor for the atomic claim.\n */\ntype Decision = null | { blocking: boolean; claimInterval: string }\n\n/**\n * Re-validates IdP-backed sessions against their identity provider on the verify hot path\n * (A24). Invoked from `ApiKeyManager.verifyAndProlong`. Operates entirely through the supplied\n * database contexts and the command bus, so it does not depend on `ApiKeyManager` (no DI cycle).\n *\n * The cadence is driven by the **access-token lifetime**, not a fixed interval:\n * - while the token is fresh (before `softRefreshThreshold` of its lifetime) → skip, free;\n * - past the threshold but not yet expired → a proactive **background (SWR)** refresh, so the\n * request keeps zero added latency and the token is renewed before it dies;\n * - once the token has actually expired → a **blocking** refresh (we can't serve a dead token).\n * `mode: 'blocking'` forces every revalidation synchronous (zero revocation lag). When the IdP\n * returns no token expiry, falls back to a plain `fallbackInterval` background throttle.\n */\nexport class IdpSessionRevalidator {\n\tconstructor(\n\t\tprivate readonly idpRegistry: IDPHandlerRegistry,\n\t) {\n\t}\n\n\tasync revalidate(\n\t\tdbContext: DatabaseContext,\n\t\treadDbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<RevalidationOutcome> {\n\t\tconst row = await readDbContext.queryHandler.fetch(new IdpSessionByApiKeyQuery(apiKeyRow.id, readDbContext.providers))\n\t\tif (!row) {\n\t\t\t// not a federated session (password / IdP without revalidation) — fast no-op\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tconst config = this.resolveConfig(row.providerConfiguration)\n\t\tif (!config.enabled) {\n\t\t\treturn 'valid'\n\t\t}\n\n\t\t// A disabled IdP no longer vouches for its sessions.\n\t\tif (row.providerDisabledAt) {\n\t\t\tawait this.revoke(dbContext, apiKeyRow, row, 'idp_disabled', requestInfo)\n\t\t\treturn 'revoked'\n\t\t}\n\n\t\tconst handler = this.idpRegistry.getHandlerOrNull(row.providerType)\n\t\tif (!handler?.revalidate) {\n\t\t\t// provider can't actively re-validate (e.g. SAML) — rely on expiry / SLO\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tconst decision = this.decide(row, config, dbContext.providers.now())\n\t\tif (!decision) {\n\t\t\t// token still fresh — vouched for, no IdP call\n\t\t\treturn 'valid'\n\t\t}\n\n\t\t// Atomic claim = single-flight. Loser (within the floor window, or lost the race) serves stale.\n\t\tlet claimed: boolean\n\t\ttry {\n\t\t\tclaimed = await dbContext.commandBus.execute(new ClaimIdpRevalidationCommand(row.id, decision.claimInterval))\n\t\t} catch {\n\t\t\t// invalid interval string or transient DB error — fail open, retry next request\n\t\t\treturn 'valid'\n\t\t}\n\t\tif (!claimed) {\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tif (decision.blocking) {\n\t\t\treturn await this.runRevalidation(dbContext, handler, row, apiKeyRow, requestInfo)\n\t\t}\n\n\t\t// SWR: serve this request from the (still valid) token, refresh after the response.\n\t\t// The work runs detached (after the response is sent), so any rejection — a transient\n\t\t// DB error in the revoke / persist writes, a corrupt-config throw — must be swallowed\n\t\t// here; otherwise it becomes an unhandledRejection and can take the worker down. The\n\t\t// session is simply kept and re-tried on a later request (the claim floor throttles).\n\t\tsetImmediate(() => {\n\t\t\tthis.runRevalidation(dbContext, handler, row, apiKeyRow, requestInfo).catch(() => {})\n\t\t})\n\t\treturn 'valid'\n\t}\n\n\t/**\n\t * Decide whether (and how) to revalidate, purely from timestamps — no interval parsing in\n\t * JS (the claim handles intervals in SQL). Returns null to skip.\n\t */\n\tprivate decide(row: IdpSessionRow, config: ResolvedRevalidationConfig, now: Date): Decision {\n\t\tconst expiresAt = row.session.expiresAt\n\t\tconst obtainedAt = row.tokenObtainedAt\n\n\t\t// No lifetime info from the IdP → plain background throttle on fallbackInterval.\n\t\tif (!expiresAt || !obtainedAt) {\n\t\t\treturn { blocking: config.mode === 'blocking', claimInterval: config.fallbackInterval }\n\t\t}\n\n\t\tconst lifetimeMs = expiresAt.getTime() - obtainedAt.getTime()\n\t\tconst softAtMs = obtainedAt.getTime() + lifetimeMs * config.softThreshold\n\t\tconst nowMs = now.getTime()\n\n\t\tif (nowMs < softAtMs) {\n\t\t\treturn null // still within the trusted window\n\t\t}\n\n\t\tconst expired = nowMs >= expiresAt.getTime()\n\t\treturn { blocking: config.mode === 'blocking' || expired, claimInterval: config.minInterval }\n\t}\n\n\tprivate async runRevalidation(\n\t\tdbContext: DatabaseContext,\n\t\thandler: IdentityProviderHandler<{}>,\n\t\trow: IdpSessionRow,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<RevalidationOutcome> {\n\t\tlet config: {}\n\t\ttry {\n\t\t\tconfig = handler.validateConfiguration(row.providerConfiguration)\n\t\t} catch {\n\t\t\t// corrupt stored config — must NOT revoke; keep the session and retry later. Audit\n\t\t\t// it so the operator can tell \"vouched for\" apart from \"silently broken\" (without an\n\t\t\t// entry, a config typo disables re-validation invisibly for the life of every session).\n\t\t\tawait this.logRevalidationFailed(dbContext, apiKeyRow, row, 'config_invalid', requestInfo)\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tlet result: RevalidationResult\n\t\ttry {\n\t\t\tresult = await handler.revalidate!(config, row.session)\n\t\t} catch {\n\t\t\t// transient failure (network / IdP down) — must NOT revoke; keep the session and retry\n\t\t\t// on a later request (the claim floor prevents hammering the IdP). Audited (throttled\n\t\t\t// to one entry per claim window) so a prolonged IdP outage is visible rather than a\n\t\t\t// silent fail-open.\n\t\t\tawait this.logRevalidationFailed(dbContext, apiKeyRow, row, 'revalidation_error', requestInfo)\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tif (result.status === 'revoked') {\n\t\t\tawait this.revoke(dbContext, apiKeyRow, row, result.reason, requestInfo)\n\t\t\treturn 'revoked'\n\t\t}\n\n\t\t// Still valid — persist the rotated token (resets the lifetime reference) / refreshed\n\t\t// expiry. A rotation is a real, low-frequency event (token-lifetime cadence), so we\n\t\t// audit it as `idp_session_revalidated`; the no-op userinfo/introspection probes\n\t\t// (no rotated session) are intentionally NOT logged to keep the audit log usable.\n\t\t//\n\t\t// The IdP has already vouched for the session, so these post-success writes are pure\n\t\t// best-effort bookkeeping (they only reset the SWR cadence reference). A transient DB\n\t\t// error or an `encrypt()` throw here must NOT fail the request — otherwise a blocking\n\t\t// revalidation fails closed on a successful refresh, contradicting \"fail open\" (the SWR\n\t\t// path already swallows this). Keep the existing row; the claim floor throttles a retry.\n\t\tif (result.idpSession) {\n\t\t\ttry {\n\t\t\t\tawait dbContext.commandBus.execute(new UpdateIdpSessionCommand(row.id, result.idpSession))\n\t\t\t\tawait this.logRevalidated(dbContext, apiKeyRow, row, requestInfo)\n\t\t\t} catch {\n\t\t\t\t// fall through — session stays valid, persist retried on a later request\n\t\t\t}\n\t\t}\n\t\treturn 'valid'\n\t}\n\n\tprivate async logRevalidated(dbContext: DatabaseContext, apiKeyRow: ApiKeyRow, row: IdpSessionRow, requestInfo?: ApiKeyRequestInfo): Promise<void> {\n\t\tawait dbContext.commandBus.execute(\n\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\ttype: 'idp_session_revalidated',\n\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\tsuccess: true,\n\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t}),\n\t\t)\n\t}\n\n\t/**\n\t * Audit a fail-open: the IdP couldn't be consulted (transient outage) or the stored config is\n\t * corrupt, so we kept the session rather than revoking it. Naturally throttled to one entry\n\t * per claim window (we only reach here after a successful claim, which bumps\n\t * `last_validated_at`). The write is best-effort and self-contained — a failure to audit must\n\t * never propagate and fail a blocking verify request (the whole point of failing open).\n\t */\n\tprivate async logRevalidationFailed(\n\t\tdbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trow: IdpSessionRow,\n\t\terrorCode: 'config_invalid' | 'revalidation_error',\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tawait dbContext.commandBus.execute(\n\t\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\t\ttype: 'idp_session_revalidation_failed',\n\t\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\t\t// not a security failure (the session is kept) — a fail-open marker the operator\n\t\t\t\t\t// can alert on. `success: true` keeps it out of the failed-login funnels.\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\terrorCode,\n\t\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t\t}),\n\t\t\t)\n\t\t} catch {\n\t\t\t// best-effort observability — never fail the request because the audit write failed\n\t\t}\n\t}\n\n\tprivate async revoke(\n\t\tdbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trow: IdpSessionRow,\n\t\treason: string,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\tawait dbContext.commandBus.execute(new DisableApiKeyCommand(apiKeyRow.id))\n\t\tawait dbContext.commandBus.execute(\n\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\ttype: 'idp_session_revoked',\n\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\tsuccess: false,\n\t\t\t\terrorCode: reason,\n\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t\t// the action payload belongs in `event_data` (where every other audit event puts\n\t\t\t\t// it and where the admin UI / AuthLogQueryResolver reads it); `metadata` is for\n\t\t\t\t// transport context (forwarder IP/UA).\n\t\t\t\teventData: { reason },\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate resolveConfig(configuration: Record<string, unknown>): ResolvedRevalidationConfig {\n\t\tconst raw = (configuration.revalidation ?? {}) as Record<string, unknown>\n\t\tconst threshold = typeof raw.softRefreshThreshold === 'number' && raw.softRefreshThreshold > 0 && raw.softRefreshThreshold <= 1\n\t\t\t? raw.softRefreshThreshold\n\t\t\t: REVALIDATION_DEFAULT_SOFT_THRESHOLD\n\t\treturn {\n\t\t\tenabled: raw.enabled === true,\n\t\t\tsoftThreshold: threshold,\n\t\t\tminInterval: typeof raw.minInterval === 'string' ? raw.minInterval : REVALIDATION_DEFAULT_MIN_INTERVAL,\n\t\t\tfallbackInterval: typeof raw.fallbackInterval === 'string' ? raw.fallbackInterval : REVALIDATION_DEFAULT_FALLBACK_INTERVAL,\n\t\t\tmode: raw.mode === 'blocking' ? 'blocking' : 'auto',\n\t\t}\n\t}\n}\n"],"names":["IdpSessionByApiKeyQuery","ClaimIdpRevalidationCommand","UpdateIdpSessionCommand","CreateAuthLogEntryCommand","DisableApiKeyCommand","REVALIDATION_DEFAULT_SOFT_THRESHOLD","REVALIDATION_DEFAULT_MIN_INTERVAL","REVALIDATION_DEFAULT_FALLBACK_INTERVAL"],"mappings":"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"}
1
+ {"version":3,"file":"IdpSessionRevalidator.cjs","sources":["../../../../../../../packages/engine-tenant-api/src/model/service/idp/IdpSessionRevalidator.ts"],"sourcesContent":["import { DatabaseContext } from '../../utils/index.js'\nimport { ApiKeyRequestInfo } from '../../commands/index.js'\nimport { ApiKeyRow } from '../../queries/apiKey/ApiKeyQuery.js'\nimport { IdpSessionByApiKeyQuery, IdpSessionRow } from '../../queries/idp/IdpSessionByApiKeyQuery.js'\nimport { IDPHandlerRegistry } from './IDPHandlerRegistry.js'\nimport { ClaimIdpRevalidationCommand } from '../../commands/idp/ClaimIdpRevalidationCommand.js'\nimport { UpdateIdpSessionCommand } from '../../commands/idp/UpdateIdpSessionCommand.js'\nimport { DisableApiKeyCommand } from '../../commands/index.js'\nimport { CreateAuthLogEntryCommand } from '../../commands/authLog/CreateAuthLogEntryCommand.js'\nimport { REVALIDATION_DEFAULT_FALLBACK_INTERVAL, REVALIDATION_DEFAULT_MIN_INTERVAL, REVALIDATION_DEFAULT_SOFT_THRESHOLD } from './IDPRevalidation.js'\nimport { IdentityProviderHandler, RevalidationResult } from './IdentityProviderHandler.js'\nimport { IDPClaimSyncService } from './IDPClaimSyncService.js'\nimport { parseClaimMapping } from './ClaimMapping.js'\nimport { JSONValue } from '@contember/schema'\n\nexport type RevalidationOutcome = 'valid' | 'revoked'\n\ntype ResolvedRevalidationConfig = {\n\tenabled: boolean\n\tsoftThreshold: number\n\tminInterval: string\n\tfallbackInterval: string\n\tmode: 'auto' | 'blocking'\n}\n\n/**\n * Decision for the current request: whether to attempt a revalidation, and if so whether it\n * must block the request. `claimInterval` is the single-flight floor for the atomic claim.\n */\ntype Decision = null | { blocking: boolean; claimInterval: string }\n\n/**\n * Re-validates IdP-backed sessions against their identity provider on the verify hot path\n * (A24). Invoked from `ApiKeyManager.verifyAndProlong`. Operates entirely through the supplied\n * database contexts and the command bus, so it does not depend on `ApiKeyManager` (no DI cycle).\n *\n * The cadence is driven by the **access-token lifetime**, not a fixed interval:\n * - while the token is fresh (before `softRefreshThreshold` of its lifetime) → skip, free;\n * - past the threshold but not yet expired → a proactive **background (SWR)** refresh, so the\n * request keeps zero added latency and the token is renewed before it dies;\n * - once the token has actually expired → a **blocking** refresh (we can't serve a dead token).\n * `mode: 'blocking'` forces every revalidation synchronous (zero revocation lag). When the IdP\n * returns no token expiry, falls back to a plain `fallbackInterval` background throttle.\n */\nexport class IdpSessionRevalidator {\n\tconstructor(\n\t\tprivate readonly idpRegistry: IDPHandlerRegistry,\n\t\tprivate readonly claimSyncService: IDPClaimSyncService,\n\t) {\n\t}\n\n\tasync revalidate(\n\t\tdbContext: DatabaseContext,\n\t\treadDbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<RevalidationOutcome> {\n\t\tconst row = await readDbContext.queryHandler.fetch(new IdpSessionByApiKeyQuery(apiKeyRow.id, readDbContext.providers))\n\t\tif (!row) {\n\t\t\t// not a federated session (password / IdP without revalidation) — fast no-op\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tconst config = this.resolveConfig(row.providerConfiguration)\n\t\tif (!config.enabled) {\n\t\t\treturn 'valid'\n\t\t}\n\n\t\t// A disabled IdP no longer vouches for its sessions.\n\t\tif (row.providerDisabledAt) {\n\t\t\tawait this.revoke(dbContext, apiKeyRow, row, 'idp_disabled', requestInfo)\n\t\t\treturn 'revoked'\n\t\t}\n\n\t\tconst handler = this.idpRegistry.getHandlerOrNull(row.providerType)\n\t\tif (!handler?.revalidate) {\n\t\t\t// provider can't actively re-validate (e.g. SAML) — rely on expiry / SLO\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tconst decision = this.decide(row, config, dbContext.providers.now())\n\t\tif (!decision) {\n\t\t\t// token still fresh — vouched for, no IdP call\n\t\t\treturn 'valid'\n\t\t}\n\n\t\t// Atomic claim = single-flight. Loser (within the floor window, or lost the race) serves stale.\n\t\tlet claimed: boolean\n\t\ttry {\n\t\t\tclaimed = await dbContext.commandBus.execute(new ClaimIdpRevalidationCommand(row.id, decision.claimInterval))\n\t\t} catch {\n\t\t\t// invalid interval string or transient DB error — fail open, retry next request\n\t\t\treturn 'valid'\n\t\t}\n\t\tif (!claimed) {\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tif (decision.blocking) {\n\t\t\treturn await this.runRevalidation(dbContext, handler, row, apiKeyRow, requestInfo)\n\t\t}\n\n\t\t// SWR: serve this request from the (still valid) token, refresh after the response.\n\t\t// The work runs detached (after the response is sent), so any rejection — a transient\n\t\t// DB error in the revoke / persist writes, a corrupt-config throw — must be swallowed\n\t\t// here; otherwise it becomes an unhandledRejection and can take the worker down. The\n\t\t// session is simply kept and re-tried on a later request (the claim floor throttles).\n\t\tsetImmediate(() => {\n\t\t\tthis.runRevalidation(dbContext, handler, row, apiKeyRow, requestInfo).catch(() => {})\n\t\t})\n\t\treturn 'valid'\n\t}\n\n\t/**\n\t * Decide whether (and how) to revalidate, purely from timestamps — no interval parsing in\n\t * JS (the claim handles intervals in SQL). Returns null to skip.\n\t */\n\tprivate decide(row: IdpSessionRow, config: ResolvedRevalidationConfig, now: Date): Decision {\n\t\tconst expiresAt = row.session.expiresAt\n\t\tconst obtainedAt = row.tokenObtainedAt\n\n\t\t// No lifetime info from the IdP → plain background throttle on fallbackInterval.\n\t\tif (!expiresAt || !obtainedAt) {\n\t\t\treturn { blocking: config.mode === 'blocking', claimInterval: config.fallbackInterval }\n\t\t}\n\n\t\tconst lifetimeMs = expiresAt.getTime() - obtainedAt.getTime()\n\t\tconst softAtMs = obtainedAt.getTime() + lifetimeMs * config.softThreshold\n\t\tconst nowMs = now.getTime()\n\n\t\tif (nowMs < softAtMs) {\n\t\t\treturn null // still within the trusted window\n\t\t}\n\n\t\tconst expired = nowMs >= expiresAt.getTime()\n\t\treturn { blocking: config.mode === 'blocking' || expired, claimInterval: config.minInterval }\n\t}\n\n\tprivate async runRevalidation(\n\t\tdbContext: DatabaseContext,\n\t\thandler: IdentityProviderHandler<{}>,\n\t\trow: IdpSessionRow,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<RevalidationOutcome> {\n\t\tlet config: {}\n\t\ttry {\n\t\t\tconfig = handler.validateConfiguration(row.providerConfiguration)\n\t\t} catch {\n\t\t\t// corrupt stored config — must NOT revoke; keep the session and retry later. Audit\n\t\t\t// it so the operator can tell \"vouched for\" apart from \"silently broken\" (without an\n\t\t\t// entry, a config typo disables re-validation invisibly for the life of every session).\n\t\t\tawait this.logRevalidationFailed(dbContext, apiKeyRow, row, 'config_invalid', requestInfo)\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tlet result: RevalidationResult\n\t\ttry {\n\t\t\tresult = await handler.revalidate!(config, row.session)\n\t\t} catch {\n\t\t\t// transient failure (network / IdP down) — must NOT revoke; keep the session and retry\n\t\t\t// on a later request (the claim floor prevents hammering the IdP). Audited (throttled\n\t\t\t// to one entry per claim window) so a prolonged IdP outage is visible rather than a\n\t\t\t// silent fail-open.\n\t\t\tawait this.logRevalidationFailed(dbContext, apiKeyRow, row, 'revalidation_error', requestInfo)\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tif (result.status === 'revoked') {\n\t\t\tawait this.revoke(dbContext, apiKeyRow, row, result.reason, requestInfo)\n\t\t\treturn 'revoked'\n\t\t}\n\n\t\t// Still valid — persist the rotated token (resets the lifetime reference) / refreshed\n\t\t// expiry. A rotation is a real, low-frequency event (token-lifetime cadence), so we\n\t\t// audit it as `idp_session_revalidated`; the no-op userinfo/introspection probes\n\t\t// (no rotated session) are intentionally NOT logged to keep the audit log usable.\n\t\t//\n\t\t// The IdP has already vouched for the session, so these post-success writes are pure\n\t\t// best-effort bookkeeping (they only reset the SWR cadence reference). A transient DB\n\t\t// error or an `encrypt()` throw here must NOT fail the request — otherwise a blocking\n\t\t// revalidation fails closed on a successful refresh, contradicting \"fail open\" (the SWR\n\t\t// path already swallows this). Keep the existing row; the claim floor throttles a retry.\n\t\tif (result.idpSession) {\n\t\t\ttry {\n\t\t\t\tawait dbContext.commandBus.execute(new UpdateIdpSessionCommand(row.id, result.idpSession))\n\t\t\t\tawait this.logRevalidated(dbContext, apiKeyRow, row, requestInfo)\n\t\t\t} catch {\n\t\t\t\t// fall through — session stays valid, persist retried on a later request\n\t\t\t}\n\t\t}\n\n\t\t// A09 — re-apply the IdP's claim mapping when the refresh returned fresh claims, so an `always`\n\t\t// mapping keeps an established session's project memberships in sync with the IdP's current claims\n\t\t// without requiring a full re-login. `sticky` mappings self-skip (the sync passes isNewPerson=false).\n\t\t// `claimsComplete` tells the sync whether the refresh rebuilt sign-in's full claim surface, so it can\n\t\t// reconcile (incl. `unmatched: \"remove\"`) exactly like sign-in. Strictly fail-open — see `syncClaims`.\n\t\tif (result.claims) {\n\t\t\tawait this.syncClaims(dbContext, row, apiKeyRow, result.claims, result.claimsComplete === true, requestInfo)\n\t\t}\n\t\treturn 'valid'\n\t}\n\n\t/**\n\t * Re-apply the claim mapping on a successful refresh. Runs in its own transaction (atomic apply of\n\t * the membership changes) and never throws: the IdP has already vouched for the session, so a\n\t * malformed mapping or a transient apply error must not revoke or fail it. A real membership change\n\t * is audited as `idp_role_mapped`; a failure is audited as `idp_role_mapping_failed` (fail-open\n\t * marker), mirroring the sign-in path. `claimsComplete` carries whether the refresh rebuilt sign-in's\n\t * full claim surface (so removal reconciliation is safe) — see `allowRemoval` below.\n\t */\n\tprivate async syncClaims(\n\t\tdbContext: DatabaseContext,\n\t\trow: IdpSessionRow,\n\t\tapiKeyRow: ApiKeyRow,\n\t\tclaims: Record<string, unknown>,\n\t\tclaimsComplete: boolean,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tconst mapping = parseClaimMapping(row.providerConfiguration)\n\t\t\tif (!mapping) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Atomic apply in its own transaction (the verify path has no surrounding one). `always`-only:\n\t\t\t// the sync passes isNewPerson=false, so a `sticky` mapping self-skips and returns a null audit.\n\t\t\t// Refresh mirrors sign-in as closely as the claim surface allows: when the provider returned its\n\t\t\t// COMPLETE surface (`claimsComplete` — `method: \"refresh\"` rebuilding sign-in's id-token + userinfo\n\t\t\t// merge), `unmatched: \"remove\"` reconciliation runs here too. A partial surface (a userinfo-only\n\t\t\t// probe, or a refresh whose userinfo fetch failed) passes `allowRemoval: false`, so refresh stays\n\t\t\t// additive-only and a membership the IdP still asserts is never stripped off an incomplete surface.\n\t\t\tconst { audit, droppedUnsafeRules } = await dbContext.transaction(db =>\n\t\t\t\tthis.claimSyncService.sync(db, mapping, claims, { id: apiKeyRow.identity_id }, false, { allowRemoval: claimsComplete })\n\t\t\t)\n\t\t\tif (audit) {\n\t\t\t\tawait this.logRoleMapping(dbContext, apiKeyRow, row, 'idp_role_mapped', audit, requestInfo)\n\t\t\t}\n\t\t\t// The apply-time safety backstop dropped a configured rule — emit the fail-open marker so a broken\n\t\t\t// mapping is visible on the refresh path too, mirroring sign-in (the marker carries no claim values).\n\t\t\tif (droppedUnsafeRules) {\n\t\t\t\tawait this.logRoleMapping(dbContext, apiKeyRow, row, 'idp_role_mapping_failed', undefined, requestInfo)\n\t\t\t}\n\t\t} catch {\n\t\t\t// Strictly fail-open: a malformed mapping or a transient apply error must never revoke or\n\t\t\t// fail an already-vouched-for session. The transaction rolls back any partial apply.\n\t\t\tawait this.logRoleMapping(dbContext, apiKeyRow, row, 'idp_role_mapping_failed', undefined, requestInfo)\n\t\t}\n\t}\n\n\tprivate async logRoleMapping(\n\t\tdbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trow: IdpSessionRow,\n\t\ttype: 'idp_role_mapped' | 'idp_role_mapping_failed',\n\t\teventData: JSONValue | undefined,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tawait dbContext.commandBus.execute(\n\t\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\t\ttype,\n\t\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\t\t// The membership change affects this session's own person — record it as the target too,\n\t\t\t\t\t// so an admin querying membership changes by target_person_id sees IdP-driven grants/revokes\n\t\t\t\t\t// (consistent with the project_membership_* audit events).\n\t\t\t\t\ttargetPersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\teventData,\n\t\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t\t}),\n\t\t\t)\n\t\t} catch {\n\t\t\t// best-effort audit — never fail the request because the audit write failed\n\t\t}\n\t}\n\n\tprivate async logRevalidated(dbContext: DatabaseContext, apiKeyRow: ApiKeyRow, row: IdpSessionRow, requestInfo?: ApiKeyRequestInfo): Promise<void> {\n\t\tawait dbContext.commandBus.execute(\n\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\ttype: 'idp_session_revalidated',\n\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\tsuccess: true,\n\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t}),\n\t\t)\n\t}\n\n\t/**\n\t * Audit a fail-open: the IdP couldn't be consulted (transient outage) or the stored config is\n\t * corrupt, so we kept the session rather than revoking it. Naturally throttled to one entry\n\t * per claim window (we only reach here after a successful claim, which bumps\n\t * `last_validated_at`). The write is best-effort and self-contained — a failure to audit must\n\t * never propagate and fail a blocking verify request (the whole point of failing open).\n\t */\n\tprivate async logRevalidationFailed(\n\t\tdbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trow: IdpSessionRow,\n\t\terrorCode: 'config_invalid' | 'revalidation_error',\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tawait dbContext.commandBus.execute(\n\t\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\t\ttype: 'idp_session_revalidation_failed',\n\t\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\t\t// not a security failure (the session is kept) — a fail-open marker the operator\n\t\t\t\t\t// can alert on. `success: true` keeps it out of the failed-login funnels.\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\terrorCode,\n\t\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t\t}),\n\t\t\t)\n\t\t} catch {\n\t\t\t// best-effort observability — never fail the request because the audit write failed\n\t\t}\n\t}\n\n\tprivate async revoke(\n\t\tdbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trow: IdpSessionRow,\n\t\treason: string,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\tawait dbContext.commandBus.execute(new DisableApiKeyCommand(apiKeyRow.id))\n\t\tawait dbContext.commandBus.execute(\n\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\ttype: 'idp_session_revoked',\n\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\tsuccess: false,\n\t\t\t\terrorCode: reason,\n\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t\t// the action payload belongs in `event_data` (where every other audit event puts\n\t\t\t\t// it and where the admin UI / AuthLogQueryResolver reads it); `metadata` is for\n\t\t\t\t// transport context (forwarder IP/UA).\n\t\t\t\teventData: { reason },\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate resolveConfig(configuration: Record<string, unknown>): ResolvedRevalidationConfig {\n\t\tconst raw = (configuration.revalidation ?? {}) as Record<string, unknown>\n\t\tconst threshold = typeof raw.softRefreshThreshold === 'number' && raw.softRefreshThreshold > 0 && raw.softRefreshThreshold <= 1\n\t\t\t? raw.softRefreshThreshold\n\t\t\t: REVALIDATION_DEFAULT_SOFT_THRESHOLD\n\t\treturn {\n\t\t\tenabled: raw.enabled === true,\n\t\t\tsoftThreshold: threshold,\n\t\t\tminInterval: typeof raw.minInterval === 'string' ? raw.minInterval : REVALIDATION_DEFAULT_MIN_INTERVAL,\n\t\t\tfallbackInterval: typeof raw.fallbackInterval === 'string' ? raw.fallbackInterval : REVALIDATION_DEFAULT_FALLBACK_INTERVAL,\n\t\t\tmode: raw.mode === 'blocking' ? 'blocking' : 'auto',\n\t\t}\n\t}\n}\n"],"names":["IdpSessionByApiKeyQuery","ClaimIdpRevalidationCommand","UpdateIdpSessionCommand","parseClaimMapping","CreateAuthLogEntryCommand","DisableApiKeyCommand","REVALIDATION_DEFAULT_SOFT_THRESHOLD","REVALIDATION_DEFAULT_MIN_INTERVAL","REVALIDATION_DEFAULT_FALLBACK_INTERVAL"],"mappings":"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"}
@@ -7,9 +7,11 @@ import "node:crypto";
7
7
  import { DisableApiKeyCommand } from "../../commands/apiKey/DisableApiKeyCommand.js";
8
8
  import { CreateAuthLogEntryCommand } from "../../commands/authLog/CreateAuthLogEntryCommand.js";
9
9
  import { REVALIDATION_DEFAULT_SOFT_THRESHOLD, REVALIDATION_DEFAULT_FALLBACK_INTERVAL, REVALIDATION_DEFAULT_MIN_INTERVAL } from "./IDPRevalidation.js";
10
+ import { parseClaimMapping } from "./ClaimMapping.js";
10
11
  class IdpSessionRevalidator {
11
- constructor(idpRegistry) {
12
+ constructor(idpRegistry, claimSyncService) {
12
13
  this.idpRegistry = idpRegistry;
14
+ this.claimSyncService = claimSyncService;
13
15
  }
14
16
  async revalidate(dbContext, readDbContext, apiKeyRow, requestInfo) {
15
17
  const row = await readDbContext.queryHandler.fetch(new IdpSessionByApiKeyQuery(apiKeyRow.id, readDbContext.providers));
@@ -95,8 +97,60 @@ class IdpSessionRevalidator {
95
97
  } catch {
96
98
  }
97
99
  }
100
+ if (result.claims) {
101
+ await this.syncClaims(dbContext, row, apiKeyRow, result.claims, result.claimsComplete === true, requestInfo);
102
+ }
98
103
  return "valid";
99
104
  }
105
+ /**
106
+ * Re-apply the claim mapping on a successful refresh. Runs in its own transaction (atomic apply of
107
+ * the membership changes) and never throws: the IdP has already vouched for the session, so a
108
+ * malformed mapping or a transient apply error must not revoke or fail it. A real membership change
109
+ * is audited as `idp_role_mapped`; a failure is audited as `idp_role_mapping_failed` (fail-open
110
+ * marker), mirroring the sign-in path. `claimsComplete` carries whether the refresh rebuilt sign-in's
111
+ * full claim surface (so removal reconciliation is safe) — see `allowRemoval` below.
112
+ */
113
+ async syncClaims(dbContext, row, apiKeyRow, claims, claimsComplete, requestInfo) {
114
+ try {
115
+ const mapping = parseClaimMapping(row.providerConfiguration);
116
+ if (!mapping) {
117
+ return;
118
+ }
119
+ const { audit, droppedUnsafeRules } = await dbContext.transaction(
120
+ (db) => this.claimSyncService.sync(db, mapping, claims, { id: apiKeyRow.identity_id }, false, { allowRemoval: claimsComplete })
121
+ );
122
+ if (audit) {
123
+ await this.logRoleMapping(dbContext, apiKeyRow, row, "idp_role_mapped", audit, requestInfo);
124
+ }
125
+ if (droppedUnsafeRules) {
126
+ await this.logRoleMapping(dbContext, apiKeyRow, row, "idp_role_mapping_failed", void 0, requestInfo);
127
+ }
128
+ } catch {
129
+ await this.logRoleMapping(dbContext, apiKeyRow, row, "idp_role_mapping_failed", void 0, requestInfo);
130
+ }
131
+ }
132
+ async logRoleMapping(dbContext, apiKeyRow, row, type, eventData, requestInfo) {
133
+ try {
134
+ await dbContext.commandBus.execute(
135
+ new CreateAuthLogEntryCommand({
136
+ type,
137
+ invokedById: apiKeyRow.identity_id,
138
+ personId: apiKeyRow.person_id ?? void 0,
139
+ // The membership change affects this session's own person — record it as the target too,
140
+ // so an admin querying membership changes by target_person_id sees IdP-driven grants/revokes
141
+ // (consistent with the project_membership_* audit events).
142
+ targetPersonId: apiKeyRow.person_id ?? void 0,
143
+ identityProviderId: row.identityProviderId,
144
+ personTokenId: apiKeyRow.id,
145
+ success: true,
146
+ eventData,
147
+ ipAddress: requestInfo?.ip,
148
+ userAgent: requestInfo?.userAgent
149
+ })
150
+ );
151
+ } catch {
152
+ }
153
+ }
100
154
  async logRevalidated(dbContext, apiKeyRow, row, requestInfo) {
101
155
  await dbContext.commandBus.execute(
102
156
  new CreateAuthLogEntryCommand({
@@ -1 +1 @@
1
- {"version":3,"file":"IdpSessionRevalidator.js","sources":["../../../../../../../packages/engine-tenant-api/src/model/service/idp/IdpSessionRevalidator.ts"],"sourcesContent":["import { DatabaseContext } from '../../utils/index.js'\nimport { ApiKeyRequestInfo } from '../../commands/index.js'\nimport { ApiKeyRow } from '../../queries/apiKey/ApiKeyQuery.js'\nimport { IdpSessionByApiKeyQuery, IdpSessionRow } from '../../queries/idp/IdpSessionByApiKeyQuery.js'\nimport { IDPHandlerRegistry } from './IDPHandlerRegistry.js'\nimport { ClaimIdpRevalidationCommand } from '../../commands/idp/ClaimIdpRevalidationCommand.js'\nimport { UpdateIdpSessionCommand } from '../../commands/idp/UpdateIdpSessionCommand.js'\nimport { DisableApiKeyCommand } from '../../commands/index.js'\nimport { CreateAuthLogEntryCommand } from '../../commands/authLog/CreateAuthLogEntryCommand.js'\nimport { REVALIDATION_DEFAULT_FALLBACK_INTERVAL, REVALIDATION_DEFAULT_MIN_INTERVAL, REVALIDATION_DEFAULT_SOFT_THRESHOLD } from './IDPRevalidation.js'\nimport { IdentityProviderHandler, RevalidationResult } from './IdentityProviderHandler.js'\n\nexport type RevalidationOutcome = 'valid' | 'revoked'\n\ntype ResolvedRevalidationConfig = {\n\tenabled: boolean\n\tsoftThreshold: number\n\tminInterval: string\n\tfallbackInterval: string\n\tmode: 'auto' | 'blocking'\n}\n\n/**\n * Decision for the current request: whether to attempt a revalidation, and if so whether it\n * must block the request. `claimInterval` is the single-flight floor for the atomic claim.\n */\ntype Decision = null | { blocking: boolean; claimInterval: string }\n\n/**\n * Re-validates IdP-backed sessions against their identity provider on the verify hot path\n * (A24). Invoked from `ApiKeyManager.verifyAndProlong`. Operates entirely through the supplied\n * database contexts and the command bus, so it does not depend on `ApiKeyManager` (no DI cycle).\n *\n * The cadence is driven by the **access-token lifetime**, not a fixed interval:\n * - while the token is fresh (before `softRefreshThreshold` of its lifetime) → skip, free;\n * - past the threshold but not yet expired → a proactive **background (SWR)** refresh, so the\n * request keeps zero added latency and the token is renewed before it dies;\n * - once the token has actually expired → a **blocking** refresh (we can't serve a dead token).\n * `mode: 'blocking'` forces every revalidation synchronous (zero revocation lag). When the IdP\n * returns no token expiry, falls back to a plain `fallbackInterval` background throttle.\n */\nexport class IdpSessionRevalidator {\n\tconstructor(\n\t\tprivate readonly idpRegistry: IDPHandlerRegistry,\n\t) {\n\t}\n\n\tasync revalidate(\n\t\tdbContext: DatabaseContext,\n\t\treadDbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<RevalidationOutcome> {\n\t\tconst row = await readDbContext.queryHandler.fetch(new IdpSessionByApiKeyQuery(apiKeyRow.id, readDbContext.providers))\n\t\tif (!row) {\n\t\t\t// not a federated session (password / IdP without revalidation) — fast no-op\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tconst config = this.resolveConfig(row.providerConfiguration)\n\t\tif (!config.enabled) {\n\t\t\treturn 'valid'\n\t\t}\n\n\t\t// A disabled IdP no longer vouches for its sessions.\n\t\tif (row.providerDisabledAt) {\n\t\t\tawait this.revoke(dbContext, apiKeyRow, row, 'idp_disabled', requestInfo)\n\t\t\treturn 'revoked'\n\t\t}\n\n\t\tconst handler = this.idpRegistry.getHandlerOrNull(row.providerType)\n\t\tif (!handler?.revalidate) {\n\t\t\t// provider can't actively re-validate (e.g. SAML) — rely on expiry / SLO\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tconst decision = this.decide(row, config, dbContext.providers.now())\n\t\tif (!decision) {\n\t\t\t// token still fresh — vouched for, no IdP call\n\t\t\treturn 'valid'\n\t\t}\n\n\t\t// Atomic claim = single-flight. Loser (within the floor window, or lost the race) serves stale.\n\t\tlet claimed: boolean\n\t\ttry {\n\t\t\tclaimed = await dbContext.commandBus.execute(new ClaimIdpRevalidationCommand(row.id, decision.claimInterval))\n\t\t} catch {\n\t\t\t// invalid interval string or transient DB error — fail open, retry next request\n\t\t\treturn 'valid'\n\t\t}\n\t\tif (!claimed) {\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tif (decision.blocking) {\n\t\t\treturn await this.runRevalidation(dbContext, handler, row, apiKeyRow, requestInfo)\n\t\t}\n\n\t\t// SWR: serve this request from the (still valid) token, refresh after the response.\n\t\t// The work runs detached (after the response is sent), so any rejection — a transient\n\t\t// DB error in the revoke / persist writes, a corrupt-config throw — must be swallowed\n\t\t// here; otherwise it becomes an unhandledRejection and can take the worker down. The\n\t\t// session is simply kept and re-tried on a later request (the claim floor throttles).\n\t\tsetImmediate(() => {\n\t\t\tthis.runRevalidation(dbContext, handler, row, apiKeyRow, requestInfo).catch(() => {})\n\t\t})\n\t\treturn 'valid'\n\t}\n\n\t/**\n\t * Decide whether (and how) to revalidate, purely from timestamps — no interval parsing in\n\t * JS (the claim handles intervals in SQL). Returns null to skip.\n\t */\n\tprivate decide(row: IdpSessionRow, config: ResolvedRevalidationConfig, now: Date): Decision {\n\t\tconst expiresAt = row.session.expiresAt\n\t\tconst obtainedAt = row.tokenObtainedAt\n\n\t\t// No lifetime info from the IdP → plain background throttle on fallbackInterval.\n\t\tif (!expiresAt || !obtainedAt) {\n\t\t\treturn { blocking: config.mode === 'blocking', claimInterval: config.fallbackInterval }\n\t\t}\n\n\t\tconst lifetimeMs = expiresAt.getTime() - obtainedAt.getTime()\n\t\tconst softAtMs = obtainedAt.getTime() + lifetimeMs * config.softThreshold\n\t\tconst nowMs = now.getTime()\n\n\t\tif (nowMs < softAtMs) {\n\t\t\treturn null // still within the trusted window\n\t\t}\n\n\t\tconst expired = nowMs >= expiresAt.getTime()\n\t\treturn { blocking: config.mode === 'blocking' || expired, claimInterval: config.minInterval }\n\t}\n\n\tprivate async runRevalidation(\n\t\tdbContext: DatabaseContext,\n\t\thandler: IdentityProviderHandler<{}>,\n\t\trow: IdpSessionRow,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<RevalidationOutcome> {\n\t\tlet config: {}\n\t\ttry {\n\t\t\tconfig = handler.validateConfiguration(row.providerConfiguration)\n\t\t} catch {\n\t\t\t// corrupt stored config — must NOT revoke; keep the session and retry later. Audit\n\t\t\t// it so the operator can tell \"vouched for\" apart from \"silently broken\" (without an\n\t\t\t// entry, a config typo disables re-validation invisibly for the life of every session).\n\t\t\tawait this.logRevalidationFailed(dbContext, apiKeyRow, row, 'config_invalid', requestInfo)\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tlet result: RevalidationResult\n\t\ttry {\n\t\t\tresult = await handler.revalidate!(config, row.session)\n\t\t} catch {\n\t\t\t// transient failure (network / IdP down) — must NOT revoke; keep the session and retry\n\t\t\t// on a later request (the claim floor prevents hammering the IdP). Audited (throttled\n\t\t\t// to one entry per claim window) so a prolonged IdP outage is visible rather than a\n\t\t\t// silent fail-open.\n\t\t\tawait this.logRevalidationFailed(dbContext, apiKeyRow, row, 'revalidation_error', requestInfo)\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tif (result.status === 'revoked') {\n\t\t\tawait this.revoke(dbContext, apiKeyRow, row, result.reason, requestInfo)\n\t\t\treturn 'revoked'\n\t\t}\n\n\t\t// Still valid — persist the rotated token (resets the lifetime reference) / refreshed\n\t\t// expiry. A rotation is a real, low-frequency event (token-lifetime cadence), so we\n\t\t// audit it as `idp_session_revalidated`; the no-op userinfo/introspection probes\n\t\t// (no rotated session) are intentionally NOT logged to keep the audit log usable.\n\t\t//\n\t\t// The IdP has already vouched for the session, so these post-success writes are pure\n\t\t// best-effort bookkeeping (they only reset the SWR cadence reference). A transient DB\n\t\t// error or an `encrypt()` throw here must NOT fail the request — otherwise a blocking\n\t\t// revalidation fails closed on a successful refresh, contradicting \"fail open\" (the SWR\n\t\t// path already swallows this). Keep the existing row; the claim floor throttles a retry.\n\t\tif (result.idpSession) {\n\t\t\ttry {\n\t\t\t\tawait dbContext.commandBus.execute(new UpdateIdpSessionCommand(row.id, result.idpSession))\n\t\t\t\tawait this.logRevalidated(dbContext, apiKeyRow, row, requestInfo)\n\t\t\t} catch {\n\t\t\t\t// fall through — session stays valid, persist retried on a later request\n\t\t\t}\n\t\t}\n\t\treturn 'valid'\n\t}\n\n\tprivate async logRevalidated(dbContext: DatabaseContext, apiKeyRow: ApiKeyRow, row: IdpSessionRow, requestInfo?: ApiKeyRequestInfo): Promise<void> {\n\t\tawait dbContext.commandBus.execute(\n\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\ttype: 'idp_session_revalidated',\n\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\tsuccess: true,\n\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t}),\n\t\t)\n\t}\n\n\t/**\n\t * Audit a fail-open: the IdP couldn't be consulted (transient outage) or the stored config is\n\t * corrupt, so we kept the session rather than revoking it. Naturally throttled to one entry\n\t * per claim window (we only reach here after a successful claim, which bumps\n\t * `last_validated_at`). The write is best-effort and self-contained — a failure to audit must\n\t * never propagate and fail a blocking verify request (the whole point of failing open).\n\t */\n\tprivate async logRevalidationFailed(\n\t\tdbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trow: IdpSessionRow,\n\t\terrorCode: 'config_invalid' | 'revalidation_error',\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tawait dbContext.commandBus.execute(\n\t\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\t\ttype: 'idp_session_revalidation_failed',\n\t\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\t\t// not a security failure (the session is kept) — a fail-open marker the operator\n\t\t\t\t\t// can alert on. `success: true` keeps it out of the failed-login funnels.\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\terrorCode,\n\t\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t\t}),\n\t\t\t)\n\t\t} catch {\n\t\t\t// best-effort observability — never fail the request because the audit write failed\n\t\t}\n\t}\n\n\tprivate async revoke(\n\t\tdbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trow: IdpSessionRow,\n\t\treason: string,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\tawait dbContext.commandBus.execute(new DisableApiKeyCommand(apiKeyRow.id))\n\t\tawait dbContext.commandBus.execute(\n\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\ttype: 'idp_session_revoked',\n\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\tsuccess: false,\n\t\t\t\terrorCode: reason,\n\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t\t// the action payload belongs in `event_data` (where every other audit event puts\n\t\t\t\t// it and where the admin UI / AuthLogQueryResolver reads it); `metadata` is for\n\t\t\t\t// transport context (forwarder IP/UA).\n\t\t\t\teventData: { reason },\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate resolveConfig(configuration: Record<string, unknown>): ResolvedRevalidationConfig {\n\t\tconst raw = (configuration.revalidation ?? {}) as Record<string, unknown>\n\t\tconst threshold = typeof raw.softRefreshThreshold === 'number' && raw.softRefreshThreshold > 0 && raw.softRefreshThreshold <= 1\n\t\t\t? raw.softRefreshThreshold\n\t\t\t: REVALIDATION_DEFAULT_SOFT_THRESHOLD\n\t\treturn {\n\t\t\tenabled: raw.enabled === true,\n\t\t\tsoftThreshold: threshold,\n\t\t\tminInterval: typeof raw.minInterval === 'string' ? raw.minInterval : REVALIDATION_DEFAULT_MIN_INTERVAL,\n\t\t\tfallbackInterval: typeof raw.fallbackInterval === 'string' ? raw.fallbackInterval : REVALIDATION_DEFAULT_FALLBACK_INTERVAL,\n\t\t\tmode: raw.mode === 'blocking' ? 'blocking' : 'auto',\n\t\t}\n\t}\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"IdpSessionRevalidator.js","sources":["../../../../../../../packages/engine-tenant-api/src/model/service/idp/IdpSessionRevalidator.ts"],"sourcesContent":["import { DatabaseContext } from '../../utils/index.js'\nimport { ApiKeyRequestInfo } from '../../commands/index.js'\nimport { ApiKeyRow } from '../../queries/apiKey/ApiKeyQuery.js'\nimport { IdpSessionByApiKeyQuery, IdpSessionRow } from '../../queries/idp/IdpSessionByApiKeyQuery.js'\nimport { IDPHandlerRegistry } from './IDPHandlerRegistry.js'\nimport { ClaimIdpRevalidationCommand } from '../../commands/idp/ClaimIdpRevalidationCommand.js'\nimport { UpdateIdpSessionCommand } from '../../commands/idp/UpdateIdpSessionCommand.js'\nimport { DisableApiKeyCommand } from '../../commands/index.js'\nimport { CreateAuthLogEntryCommand } from '../../commands/authLog/CreateAuthLogEntryCommand.js'\nimport { REVALIDATION_DEFAULT_FALLBACK_INTERVAL, REVALIDATION_DEFAULT_MIN_INTERVAL, REVALIDATION_DEFAULT_SOFT_THRESHOLD } from './IDPRevalidation.js'\nimport { IdentityProviderHandler, RevalidationResult } from './IdentityProviderHandler.js'\nimport { IDPClaimSyncService } from './IDPClaimSyncService.js'\nimport { parseClaimMapping } from './ClaimMapping.js'\nimport { JSONValue } from '@contember/schema'\n\nexport type RevalidationOutcome = 'valid' | 'revoked'\n\ntype ResolvedRevalidationConfig = {\n\tenabled: boolean\n\tsoftThreshold: number\n\tminInterval: string\n\tfallbackInterval: string\n\tmode: 'auto' | 'blocking'\n}\n\n/**\n * Decision for the current request: whether to attempt a revalidation, and if so whether it\n * must block the request. `claimInterval` is the single-flight floor for the atomic claim.\n */\ntype Decision = null | { blocking: boolean; claimInterval: string }\n\n/**\n * Re-validates IdP-backed sessions against their identity provider on the verify hot path\n * (A24). Invoked from `ApiKeyManager.verifyAndProlong`. Operates entirely through the supplied\n * database contexts and the command bus, so it does not depend on `ApiKeyManager` (no DI cycle).\n *\n * The cadence is driven by the **access-token lifetime**, not a fixed interval:\n * - while the token is fresh (before `softRefreshThreshold` of its lifetime) → skip, free;\n * - past the threshold but not yet expired → a proactive **background (SWR)** refresh, so the\n * request keeps zero added latency and the token is renewed before it dies;\n * - once the token has actually expired → a **blocking** refresh (we can't serve a dead token).\n * `mode: 'blocking'` forces every revalidation synchronous (zero revocation lag). When the IdP\n * returns no token expiry, falls back to a plain `fallbackInterval` background throttle.\n */\nexport class IdpSessionRevalidator {\n\tconstructor(\n\t\tprivate readonly idpRegistry: IDPHandlerRegistry,\n\t\tprivate readonly claimSyncService: IDPClaimSyncService,\n\t) {\n\t}\n\n\tasync revalidate(\n\t\tdbContext: DatabaseContext,\n\t\treadDbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<RevalidationOutcome> {\n\t\tconst row = await readDbContext.queryHandler.fetch(new IdpSessionByApiKeyQuery(apiKeyRow.id, readDbContext.providers))\n\t\tif (!row) {\n\t\t\t// not a federated session (password / IdP without revalidation) — fast no-op\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tconst config = this.resolveConfig(row.providerConfiguration)\n\t\tif (!config.enabled) {\n\t\t\treturn 'valid'\n\t\t}\n\n\t\t// A disabled IdP no longer vouches for its sessions.\n\t\tif (row.providerDisabledAt) {\n\t\t\tawait this.revoke(dbContext, apiKeyRow, row, 'idp_disabled', requestInfo)\n\t\t\treturn 'revoked'\n\t\t}\n\n\t\tconst handler = this.idpRegistry.getHandlerOrNull(row.providerType)\n\t\tif (!handler?.revalidate) {\n\t\t\t// provider can't actively re-validate (e.g. SAML) — rely on expiry / SLO\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tconst decision = this.decide(row, config, dbContext.providers.now())\n\t\tif (!decision) {\n\t\t\t// token still fresh — vouched for, no IdP call\n\t\t\treturn 'valid'\n\t\t}\n\n\t\t// Atomic claim = single-flight. Loser (within the floor window, or lost the race) serves stale.\n\t\tlet claimed: boolean\n\t\ttry {\n\t\t\tclaimed = await dbContext.commandBus.execute(new ClaimIdpRevalidationCommand(row.id, decision.claimInterval))\n\t\t} catch {\n\t\t\t// invalid interval string or transient DB error — fail open, retry next request\n\t\t\treturn 'valid'\n\t\t}\n\t\tif (!claimed) {\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tif (decision.blocking) {\n\t\t\treturn await this.runRevalidation(dbContext, handler, row, apiKeyRow, requestInfo)\n\t\t}\n\n\t\t// SWR: serve this request from the (still valid) token, refresh after the response.\n\t\t// The work runs detached (after the response is sent), so any rejection — a transient\n\t\t// DB error in the revoke / persist writes, a corrupt-config throw — must be swallowed\n\t\t// here; otherwise it becomes an unhandledRejection and can take the worker down. The\n\t\t// session is simply kept and re-tried on a later request (the claim floor throttles).\n\t\tsetImmediate(() => {\n\t\t\tthis.runRevalidation(dbContext, handler, row, apiKeyRow, requestInfo).catch(() => {})\n\t\t})\n\t\treturn 'valid'\n\t}\n\n\t/**\n\t * Decide whether (and how) to revalidate, purely from timestamps — no interval parsing in\n\t * JS (the claim handles intervals in SQL). Returns null to skip.\n\t */\n\tprivate decide(row: IdpSessionRow, config: ResolvedRevalidationConfig, now: Date): Decision {\n\t\tconst expiresAt = row.session.expiresAt\n\t\tconst obtainedAt = row.tokenObtainedAt\n\n\t\t// No lifetime info from the IdP → plain background throttle on fallbackInterval.\n\t\tif (!expiresAt || !obtainedAt) {\n\t\t\treturn { blocking: config.mode === 'blocking', claimInterval: config.fallbackInterval }\n\t\t}\n\n\t\tconst lifetimeMs = expiresAt.getTime() - obtainedAt.getTime()\n\t\tconst softAtMs = obtainedAt.getTime() + lifetimeMs * config.softThreshold\n\t\tconst nowMs = now.getTime()\n\n\t\tif (nowMs < softAtMs) {\n\t\t\treturn null // still within the trusted window\n\t\t}\n\n\t\tconst expired = nowMs >= expiresAt.getTime()\n\t\treturn { blocking: config.mode === 'blocking' || expired, claimInterval: config.minInterval }\n\t}\n\n\tprivate async runRevalidation(\n\t\tdbContext: DatabaseContext,\n\t\thandler: IdentityProviderHandler<{}>,\n\t\trow: IdpSessionRow,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<RevalidationOutcome> {\n\t\tlet config: {}\n\t\ttry {\n\t\t\tconfig = handler.validateConfiguration(row.providerConfiguration)\n\t\t} catch {\n\t\t\t// corrupt stored config — must NOT revoke; keep the session and retry later. Audit\n\t\t\t// it so the operator can tell \"vouched for\" apart from \"silently broken\" (without an\n\t\t\t// entry, a config typo disables re-validation invisibly for the life of every session).\n\t\t\tawait this.logRevalidationFailed(dbContext, apiKeyRow, row, 'config_invalid', requestInfo)\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tlet result: RevalidationResult\n\t\ttry {\n\t\t\tresult = await handler.revalidate!(config, row.session)\n\t\t} catch {\n\t\t\t// transient failure (network / IdP down) — must NOT revoke; keep the session and retry\n\t\t\t// on a later request (the claim floor prevents hammering the IdP). Audited (throttled\n\t\t\t// to one entry per claim window) so a prolonged IdP outage is visible rather than a\n\t\t\t// silent fail-open.\n\t\t\tawait this.logRevalidationFailed(dbContext, apiKeyRow, row, 'revalidation_error', requestInfo)\n\t\t\treturn 'valid'\n\t\t}\n\n\t\tif (result.status === 'revoked') {\n\t\t\tawait this.revoke(dbContext, apiKeyRow, row, result.reason, requestInfo)\n\t\t\treturn 'revoked'\n\t\t}\n\n\t\t// Still valid — persist the rotated token (resets the lifetime reference) / refreshed\n\t\t// expiry. A rotation is a real, low-frequency event (token-lifetime cadence), so we\n\t\t// audit it as `idp_session_revalidated`; the no-op userinfo/introspection probes\n\t\t// (no rotated session) are intentionally NOT logged to keep the audit log usable.\n\t\t//\n\t\t// The IdP has already vouched for the session, so these post-success writes are pure\n\t\t// best-effort bookkeeping (they only reset the SWR cadence reference). A transient DB\n\t\t// error or an `encrypt()` throw here must NOT fail the request — otherwise a blocking\n\t\t// revalidation fails closed on a successful refresh, contradicting \"fail open\" (the SWR\n\t\t// path already swallows this). Keep the existing row; the claim floor throttles a retry.\n\t\tif (result.idpSession) {\n\t\t\ttry {\n\t\t\t\tawait dbContext.commandBus.execute(new UpdateIdpSessionCommand(row.id, result.idpSession))\n\t\t\t\tawait this.logRevalidated(dbContext, apiKeyRow, row, requestInfo)\n\t\t\t} catch {\n\t\t\t\t// fall through — session stays valid, persist retried on a later request\n\t\t\t}\n\t\t}\n\n\t\t// A09 — re-apply the IdP's claim mapping when the refresh returned fresh claims, so an `always`\n\t\t// mapping keeps an established session's project memberships in sync with the IdP's current claims\n\t\t// without requiring a full re-login. `sticky` mappings self-skip (the sync passes isNewPerson=false).\n\t\t// `claimsComplete` tells the sync whether the refresh rebuilt sign-in's full claim surface, so it can\n\t\t// reconcile (incl. `unmatched: \"remove\"`) exactly like sign-in. Strictly fail-open — see `syncClaims`.\n\t\tif (result.claims) {\n\t\t\tawait this.syncClaims(dbContext, row, apiKeyRow, result.claims, result.claimsComplete === true, requestInfo)\n\t\t}\n\t\treturn 'valid'\n\t}\n\n\t/**\n\t * Re-apply the claim mapping on a successful refresh. Runs in its own transaction (atomic apply of\n\t * the membership changes) and never throws: the IdP has already vouched for the session, so a\n\t * malformed mapping or a transient apply error must not revoke or fail it. A real membership change\n\t * is audited as `idp_role_mapped`; a failure is audited as `idp_role_mapping_failed` (fail-open\n\t * marker), mirroring the sign-in path. `claimsComplete` carries whether the refresh rebuilt sign-in's\n\t * full claim surface (so removal reconciliation is safe) — see `allowRemoval` below.\n\t */\n\tprivate async syncClaims(\n\t\tdbContext: DatabaseContext,\n\t\trow: IdpSessionRow,\n\t\tapiKeyRow: ApiKeyRow,\n\t\tclaims: Record<string, unknown>,\n\t\tclaimsComplete: boolean,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tconst mapping = parseClaimMapping(row.providerConfiguration)\n\t\t\tif (!mapping) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Atomic apply in its own transaction (the verify path has no surrounding one). `always`-only:\n\t\t\t// the sync passes isNewPerson=false, so a `sticky` mapping self-skips and returns a null audit.\n\t\t\t// Refresh mirrors sign-in as closely as the claim surface allows: when the provider returned its\n\t\t\t// COMPLETE surface (`claimsComplete` — `method: \"refresh\"` rebuilding sign-in's id-token + userinfo\n\t\t\t// merge), `unmatched: \"remove\"` reconciliation runs here too. A partial surface (a userinfo-only\n\t\t\t// probe, or a refresh whose userinfo fetch failed) passes `allowRemoval: false`, so refresh stays\n\t\t\t// additive-only and a membership the IdP still asserts is never stripped off an incomplete surface.\n\t\t\tconst { audit, droppedUnsafeRules } = await dbContext.transaction(db =>\n\t\t\t\tthis.claimSyncService.sync(db, mapping, claims, { id: apiKeyRow.identity_id }, false, { allowRemoval: claimsComplete })\n\t\t\t)\n\t\t\tif (audit) {\n\t\t\t\tawait this.logRoleMapping(dbContext, apiKeyRow, row, 'idp_role_mapped', audit, requestInfo)\n\t\t\t}\n\t\t\t// The apply-time safety backstop dropped a configured rule — emit the fail-open marker so a broken\n\t\t\t// mapping is visible on the refresh path too, mirroring sign-in (the marker carries no claim values).\n\t\t\tif (droppedUnsafeRules) {\n\t\t\t\tawait this.logRoleMapping(dbContext, apiKeyRow, row, 'idp_role_mapping_failed', undefined, requestInfo)\n\t\t\t}\n\t\t} catch {\n\t\t\t// Strictly fail-open: a malformed mapping or a transient apply error must never revoke or\n\t\t\t// fail an already-vouched-for session. The transaction rolls back any partial apply.\n\t\t\tawait this.logRoleMapping(dbContext, apiKeyRow, row, 'idp_role_mapping_failed', undefined, requestInfo)\n\t\t}\n\t}\n\n\tprivate async logRoleMapping(\n\t\tdbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trow: IdpSessionRow,\n\t\ttype: 'idp_role_mapped' | 'idp_role_mapping_failed',\n\t\teventData: JSONValue | undefined,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tawait dbContext.commandBus.execute(\n\t\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\t\ttype,\n\t\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\t\t// The membership change affects this session's own person — record it as the target too,\n\t\t\t\t\t// so an admin querying membership changes by target_person_id sees IdP-driven grants/revokes\n\t\t\t\t\t// (consistent with the project_membership_* audit events).\n\t\t\t\t\ttargetPersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\teventData,\n\t\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t\t}),\n\t\t\t)\n\t\t} catch {\n\t\t\t// best-effort audit — never fail the request because the audit write failed\n\t\t}\n\t}\n\n\tprivate async logRevalidated(dbContext: DatabaseContext, apiKeyRow: ApiKeyRow, row: IdpSessionRow, requestInfo?: ApiKeyRequestInfo): Promise<void> {\n\t\tawait dbContext.commandBus.execute(\n\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\ttype: 'idp_session_revalidated',\n\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\tsuccess: true,\n\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t}),\n\t\t)\n\t}\n\n\t/**\n\t * Audit a fail-open: the IdP couldn't be consulted (transient outage) or the stored config is\n\t * corrupt, so we kept the session rather than revoking it. Naturally throttled to one entry\n\t * per claim window (we only reach here after a successful claim, which bumps\n\t * `last_validated_at`). The write is best-effort and self-contained — a failure to audit must\n\t * never propagate and fail a blocking verify request (the whole point of failing open).\n\t */\n\tprivate async logRevalidationFailed(\n\t\tdbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trow: IdpSessionRow,\n\t\terrorCode: 'config_invalid' | 'revalidation_error',\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\ttry {\n\t\t\tawait dbContext.commandBus.execute(\n\t\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\t\ttype: 'idp_session_revalidation_failed',\n\t\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\t\t// not a security failure (the session is kept) — a fail-open marker the operator\n\t\t\t\t\t// can alert on. `success: true` keeps it out of the failed-login funnels.\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\terrorCode,\n\t\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t\t}),\n\t\t\t)\n\t\t} catch {\n\t\t\t// best-effort observability — never fail the request because the audit write failed\n\t\t}\n\t}\n\n\tprivate async revoke(\n\t\tdbContext: DatabaseContext,\n\t\tapiKeyRow: ApiKeyRow,\n\t\trow: IdpSessionRow,\n\t\treason: string,\n\t\trequestInfo?: ApiKeyRequestInfo,\n\t): Promise<void> {\n\t\tawait dbContext.commandBus.execute(new DisableApiKeyCommand(apiKeyRow.id))\n\t\tawait dbContext.commandBus.execute(\n\t\t\tnew CreateAuthLogEntryCommand({\n\t\t\t\ttype: 'idp_session_revoked',\n\t\t\t\tinvokedById: apiKeyRow.identity_id,\n\t\t\t\tpersonId: apiKeyRow.person_id ?? undefined,\n\t\t\t\tidentityProviderId: row.identityProviderId,\n\t\t\t\tpersonTokenId: apiKeyRow.id,\n\t\t\t\tsuccess: false,\n\t\t\t\terrorCode: reason,\n\t\t\t\tipAddress: requestInfo?.ip,\n\t\t\t\tuserAgent: requestInfo?.userAgent,\n\t\t\t\t// the action payload belongs in `event_data` (where every other audit event puts\n\t\t\t\t// it and where the admin UI / AuthLogQueryResolver reads it); `metadata` is for\n\t\t\t\t// transport context (forwarder IP/UA).\n\t\t\t\teventData: { reason },\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate resolveConfig(configuration: Record<string, unknown>): ResolvedRevalidationConfig {\n\t\tconst raw = (configuration.revalidation ?? {}) as Record<string, unknown>\n\t\tconst threshold = typeof raw.softRefreshThreshold === 'number' && raw.softRefreshThreshold > 0 && raw.softRefreshThreshold <= 1\n\t\t\t? raw.softRefreshThreshold\n\t\t\t: REVALIDATION_DEFAULT_SOFT_THRESHOLD\n\t\treturn {\n\t\t\tenabled: raw.enabled === true,\n\t\t\tsoftThreshold: threshold,\n\t\t\tminInterval: typeof raw.minInterval === 'string' ? raw.minInterval : REVALIDATION_DEFAULT_MIN_INTERVAL,\n\t\t\tfallbackInterval: typeof raw.fallbackInterval === 'string' ? raw.fallbackInterval : REVALIDATION_DEFAULT_FALLBACK_INTERVAL,\n\t\t\tmode: raw.mode === 'blocking' ? 'blocking' : 'auto',\n\t\t}\n\t}\n}\n"],"names":[],"mappings":"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"}
@@ -33,9 +33,56 @@ const initOIDCAuth = async (client, { redirectUrl, scope, responseMode }) => {
33
33
  };
34
34
  };
35
35
  const getClaim = (source, path) => path.split(".").reduce(
36
- (acc, key) => acc != null && typeof acc === "object" ? acc[key] : void 0,
36
+ (acc, key) => acc != null && typeof acc === "object" && Object.prototype.hasOwnProperty.call(acc, key) ? acc[key] : void 0,
37
37
  source
38
38
  );
39
+ const liftNestedClaims = (source, attributesKey) => {
40
+ if (!attributesKey) {
41
+ return source;
42
+ }
43
+ const nested = Object.prototype.hasOwnProperty.call(source, attributesKey) ? source[attributesKey] : void 0;
44
+ if (nested !== null && typeof nested === "object" && !Array.isArray(nested)) {
45
+ return { ...nested, ...source };
46
+ }
47
+ return source;
48
+ };
49
+ const normalizeClaims = (rawSource, claimMapping, subFallback) => {
50
+ const source = liftNestedClaims(rawSource, claimMapping?.attributesKey);
51
+ const rawEmailVerified = source.email_verified;
52
+ const emailVerified = rawEmailVerified === true || rawEmailVerified === "true";
53
+ const mappedSubject = getClaim(source, claimMapping?.externalIdentifier ?? "sub");
54
+ let externalIdentifier;
55
+ if (mappedSubject === void 0 || mappedSubject === null) {
56
+ externalIdentifier = subFallback ?? "";
57
+ } else if (typeof mappedSubject === "string" || typeof mappedSubject === "number") {
58
+ externalIdentifier = String(mappedSubject);
59
+ } else {
60
+ throw new IDPValidationError.IDPValidationError(`The mapped externalIdentifier claim is not a scalar value`);
61
+ }
62
+ if (externalIdentifier === "") {
63
+ throw new IDPValidationError.IDPValidationError(`The mapped externalIdentifier claim resolved to an empty value`);
64
+ }
65
+ const email = getClaim(source, claimMapping?.email ?? "email");
66
+ const name = resolveName(source, claimMapping);
67
+ return {
68
+ ...source,
69
+ externalIdentifier,
70
+ email: typeof email === "string" ? email : void 0,
71
+ name,
72
+ emailVerified
73
+ };
74
+ };
75
+ const resolveName = (source, claimMapping) => {
76
+ const mapped = getClaim(source, claimMapping?.name ?? "name");
77
+ if (typeof mapped === "string" && mapped.trim() !== "") {
78
+ return mapped;
79
+ }
80
+ if (claimMapping?.name !== void 0) {
81
+ return void 0;
82
+ }
83
+ const parts = [getClaim(source, "given_name"), getClaim(source, "family_name")].filter((part) => typeof part === "string" && part.trim() !== "").map((part) => part.trim());
84
+ return parts.length > 0 ? parts.join(" ") : void 0;
85
+ };
39
86
  const handleOIDCResponse = async (client, { sessionData, redirectUrl, ...otherData }, { fetchUserInfo, returnOIDCResult, captureSession, claimMapping } = {}) => {
40
87
  const params = "parameters" in otherData ? otherData.parameters : client.callbackParams(otherData.url);
41
88
  if (params.state && !sessionData?.state) {
@@ -48,37 +95,10 @@ const handleOIDCResponse = async (client, { sessionData, redirectUrl, ...otherDa
48
95
  const userInfo = result.access_token && fetchUserInfo ? await client.userinfo(result) : {};
49
96
  const oidcResult = returnOIDCResult ? result : {};
50
97
  const idpSession = captureSession ? tokenSetToSessionState(result, typeof claims.sid === "string" ? claims.sid : void 0) : void 0;
51
- let source = { ...claimsWithoutHashes, ...userInfo };
52
- const attributesKey = claimMapping?.attributesKey;
53
- if (attributesKey) {
54
- const nested = source[attributesKey];
55
- if (nested && typeof nested === "object" && !Array.isArray(nested)) {
56
- source = { ...nested, ...source };
57
- }
58
- }
59
- const rawEmailVerified = source.email_verified;
60
- const emailVerified = rawEmailVerified === true || rawEmailVerified === "true";
61
- const mappedSubject = getClaim(source, claimMapping?.externalIdentifier ?? "sub");
62
- let externalIdentifier;
63
- if (mappedSubject === void 0 || mappedSubject === null) {
64
- externalIdentifier = claims.sub;
65
- } else if (typeof mappedSubject === "string" || typeof mappedSubject === "number") {
66
- externalIdentifier = String(mappedSubject);
67
- } else {
68
- throw new IDPValidationError.IDPValidationError(`The mapped externalIdentifier claim is not a scalar value`);
69
- }
70
- if (externalIdentifier === "") {
71
- throw new IDPValidationError.IDPValidationError(`The mapped externalIdentifier claim resolved to an empty value`);
72
- }
73
- const email = getClaim(source, claimMapping?.email ?? "email");
74
- const name = getClaim(source, claimMapping?.name ?? "name");
98
+ const normalized = normalizeClaims({ ...claimsWithoutHashes, ...userInfo }, claimMapping, claims.sub);
75
99
  return {
76
100
  ...oidcResult,
77
- ...source,
78
- externalIdentifier,
79
- email: typeof email === "string" ? email : void 0,
80
- name: typeof name === "string" ? name : void 0,
81
- emailVerified,
101
+ ...normalized,
82
102
  ...idpSession ? { idpSession } : {}
83
103
  };
84
104
  } catch (e) {
@@ -96,7 +116,8 @@ const handleOIDCResponse = async (client, { sessionData, redirectUrl, ...otherDa
96
116
  }
97
117
  };
98
118
  const REVOKED_OIDC_ERRORS = /* @__PURE__ */ new Set(["invalid_grant", "invalid_token", "expired_token"]);
99
- const revalidateOIDC = async (client, method, session) => {
119
+ const revalidateOIDC = async (client, method, session, options = {}) => {
120
+ const { claimMapping, fetchUserInfo } = options;
100
121
  const tokens = session.tokens ?? {};
101
122
  const refreshToken = typeof tokens.refresh_token === "string" ? tokens.refresh_token : void 0;
102
123
  const accessToken = typeof tokens.access_token === "string" ? tokens.access_token : void 0;
@@ -107,14 +128,22 @@ const revalidateOIDC = async (client, method, session) => {
107
128
  }
108
129
  const tokenSet = await client.refresh(refreshToken);
109
130
  let claims;
131
+ let claimsComplete = false;
110
132
  try {
111
- claims = tokenSet.id_token ? tokenSet.claims() : void 0;
133
+ if (tokenSet.id_token) {
134
+ const idClaims = tokenSet.claims();
135
+ const userInfo = tokenSet.access_token && fetchUserInfo ? await client.userinfo(tokenSet) : {};
136
+ claims = normalizeClaims({ ...idClaims, ...userInfo }, claimMapping, typeof idClaims.sub === "string" ? idClaims.sub : void 0);
137
+ claimsComplete = true;
138
+ }
112
139
  } catch {
113
140
  claims = void 0;
141
+ claimsComplete = false;
114
142
  }
115
143
  return {
116
144
  status: "valid",
117
145
  claims,
146
+ claimsComplete,
118
147
  // carry the stored tokens forward: a non-rotating IdP omits the refresh token here
119
148
  idpSession: tokenSetToSessionState(tokenSet, session.sessionId, tokens)
120
149
  };
@@ -124,7 +153,13 @@ const revalidateOIDC = async (client, method, session) => {
124
153
  return { status: "revoked", reason: "no_access_token" };
125
154
  }
126
155
  const userInfo = await client.userinfo(accessToken);
127
- return { status: "valid", claims: userInfo };
156
+ let claims;
157
+ try {
158
+ claims = normalizeClaims(userInfo, claimMapping, typeof userInfo.sub === "string" ? userInfo.sub : void 0);
159
+ } catch {
160
+ claims = void 0;
161
+ }
162
+ return { status: "valid", claims, claimsComplete: false };
128
163
  }
129
164
  const token = accessToken ?? refreshToken;
130
165
  if (!token) {
@@ -215,6 +250,7 @@ const validateOIDCLogoutToken = async (client, issuer, logoutToken) => {
215
250
  exports.buildOIDCLogoutUrl = buildOIDCLogoutUrl;
216
251
  exports.handleOIDCResponse = handleOIDCResponse;
217
252
  exports.initOIDCAuth = initOIDCAuth;
253
+ exports.liftNestedClaims = liftNestedClaims;
218
254
  exports.revalidateOIDC = revalidateOIDC;
219
255
  exports.tokenSetToSessionState = tokenSetToSessionState;
220
256
  exports.validateOIDCLogoutToken = validateOIDCLogoutToken;
@@ -1 +1 @@
1
- {"version":3,"file":"OIDCHelpers.cjs","sources":["../../../../../../../../packages/engine-tenant-api/src/model/service/idp/providers/OIDCHelpers.ts"],"sourcesContent":["import { Client, custom, errors, generators, Issuer, TokenSet } from 'openid-client'\nimport { createRemoteJWKSet, jwtVerify } from 'jose'\nimport { OIDCClaimMapping, OIDCResponseData } from './OIDCTypes.js'\nimport { IDPValidationError } from '../IDPValidationError.js'\nimport { IDPResponseError } from '../IDPResponseError.js'\nimport {\n\tIDPResponse,\n\tIDPSessionState,\n\tInitIDPAuthResult,\n\tLogoutTokenClaims,\n\tLogoutUrlRequest,\n\tRevalidationResult,\n} from '../IdentityProviderHandler.js'\n\n/**\n * Build the persisted session state from an OIDC token set. Stores the tokens needed for\n * later re-validation (refresh/access) and SLO (id_token); the whole `tokens` blob is\n * encrypted at rest by the command layer.\n *\n * `prevTokens` carries the previously stored tokens forward: a refresh-grant response MAY omit\n * the refresh token (RFC 6749 §6 — IdPs that don't rotate just don't re-send it), in which case\n * the client must keep using the old one. Without this fallback a non-rotating IdP would persist\n * a session with no refresh token and be revoked (`no_refresh_token`) on the very next tick.\n */\nexport const tokenSetToSessionState = (tokenSet: TokenSet, sessionId?: string, prevTokens?: Record<string, unknown>): IDPSessionState => {\n\tconst refreshToken = tokenSet.refresh_token ?? (typeof prevTokens?.refresh_token === 'string' ? prevTokens.refresh_token : undefined)\n\tconst idToken = tokenSet.id_token ?? (typeof prevTokens?.id_token === 'string' ? prevTokens.id_token : undefined)\n\treturn {\n\t\tsessionId,\n\t\ttokens: {\n\t\t\t...(refreshToken ? { refresh_token: refreshToken } : {}),\n\t\t\t...(tokenSet.access_token ? { access_token: tokenSet.access_token } : {}),\n\t\t\t...(idToken ? { id_token: idToken } : {}),\n\t\t},\n\t\texpiresAt: tokenSet.expires_at ? new Date(tokenSet.expires_at * 1000) : undefined,\n\t}\n}\n\nexport const initOIDCAuth = async (\n\tclient: Client,\n\t{ redirectUrl, scope, responseMode }: { redirectUrl: string; scope?: string; responseMode?: string },\n): Promise<InitIDPAuthResult> => {\n\tconst nonce = generators.nonce()\n\tconst state = generators.state()\n\tconst url = client.authorizationUrl({\n\t\tredirect_uri: redirectUrl,\n\t\tresponse_mode: responseMode,\n\t\tscope: scope ?? 'openid email',\n\t\tnonce,\n\t\tstate,\n\t})\n\n\treturn {\n\t\tauthUrl: url,\n\t\tsessionData: { nonce, state },\n\t}\n}\n\nexport type HandleOIDCResponseOptions = {\n\tfetchUserInfo?: boolean\n\treturnOIDCResult?: boolean\n\tcaptureSession?: boolean\n\tclaimMapping?: OIDCClaimMapping\n}\n\n/** Read a claim by name, supporting dot-paths into nested objects (`a.b.c`). */\nconst getClaim = (source: Record<string, unknown>, path: string): unknown =>\n\tpath.split('.').reduce<unknown>(\n\t\t(acc, key) => (acc != null && typeof acc === 'object' ? (acc as Record<string, unknown>)[key] : undefined),\n\t\tsource,\n\t)\n\nexport const handleOIDCResponse = async (\n\tclient: Client,\n\t{ sessionData, redirectUrl, ...otherData }: OIDCResponseData,\n\t{ fetchUserInfo, returnOIDCResult, captureSession, claimMapping }: HandleOIDCResponseOptions = {},\n): Promise<IDPResponse> => {\n\tconst params = 'parameters' in otherData ? otherData.parameters : client.callbackParams(otherData.url)\n\tif (params.state && !sessionData?.state) {\n\t\tthrow new IDPValidationError(`state is present in parameters, but missing in session data`)\n\t}\n\ttry {\n\t\tconst result = await client.callback(redirectUrl, params, sessionData)\n\t\tconst claims = result.claims()\n\t\tconst { at_hash, c_hash, nonce, ...claimsWithoutHashes } = claims\n\t\tconst userInfo = result.access_token && fetchUserInfo ? await client.userinfo(result) : {}\n\t\tconst oidcResult = returnOIDCResult ? result : {}\n\t\tconst idpSession = captureSession ? tokenSetToSessionState(result, typeof claims.sid === 'string' ? claims.sid : undefined) : undefined\n\n\t\t// Merge ID-token claims with userInfo (userInfo wins, per spec). Then optionally lift a\n\t\t// nested attributes object to the top level so providers that nest their claims (notably\n\t\t// Apereo CAS userinfo, which returns them under `attributes`) map without a code change.\n\t\t// The nested attributes are UNSIGNED, so they must not override a claim already present in\n\t\t// the (signature-verified) ID-token / userInfo merge — spread them UNDER `source`, not over\n\t\t// it, so a signed `sub` / `email_verified` keeps precedence over an attributes-level value.\n\t\tlet source: Record<string, unknown> = { ...claimsWithoutHashes, ...userInfo }\n\t\tconst attributesKey = claimMapping?.attributesKey\n\t\tif (attributesKey) {\n\t\t\tconst nested = source[attributesKey]\n\t\t\tif (nested && typeof nested === 'object' && !Array.isArray(nested)) {\n\t\t\t\tsource = { ...(nested as Record<string, unknown>), ...source }\n\t\t\t}\n\t\t}\n\n\t\t// The OIDC `email_verified` claim is a boolean per spec, but some providers send the\n\t\t// string \"true\". userInfo (and any unwrapped attributes) take precedence over the ID token.\n\t\tconst rawEmailVerified = source.email_verified\n\t\tconst emailVerified = rawEmailVerified === true || rawEmailVerified === 'true'\n\n\t\t// `externalIdentifier` is the federation key persisted in `person_identity_provider` and\n\t\t// matched on the next sign-in, so it must be a stable scalar. A `claimMapping` that pointed\n\t\t// it at an object/array would otherwise be coerced by `String(...)` to `'[object Object]'` /\n\t\t// a comma-join — collapsing every user of the provider onto one key (account takeover). Fail\n\t\t// closed instead. The default `sub` path is safe (openid-client guarantees `sub` is a string).\n\t\tconst mappedSubject = getClaim(source, claimMapping?.externalIdentifier ?? 'sub')\n\t\tlet externalIdentifier: string\n\t\tif (mappedSubject === undefined || mappedSubject === null) {\n\t\t\texternalIdentifier = claims.sub\n\t\t} else if (typeof mappedSubject === 'string' || typeof mappedSubject === 'number') {\n\t\t\texternalIdentifier = String(mappedSubject)\n\t\t} else {\n\t\t\tthrow new IDPValidationError(`The mapped externalIdentifier claim is not a scalar value`)\n\t\t}\n\t\tif (externalIdentifier === '') {\n\t\t\tthrow new IDPValidationError(`The mapped externalIdentifier claim resolved to an empty value`)\n\t\t}\n\n\t\t// `email` / `name` are typed `string | undefined` on IDPResponse and feed the by-e-mail\n\t\t// account lookup (which crashes on a non-string). `...source` already placed the raw claim\n\t\t// of whatever type, so OVERWRITE (don't conditionally add) with the mapped value when it is\n\t\t// a string, otherwise `undefined` — a non-string claim must not leak through `...source`.\n\t\tconst email = getClaim(source, claimMapping?.email ?? 'email')\n\t\tconst name = getClaim(source, claimMapping?.name ?? 'name')\n\n\t\treturn {\n\t\t\t...oidcResult,\n\t\t\t...source,\n\t\t\texternalIdentifier,\n\t\t\temail: typeof email === 'string' ? email : undefined,\n\t\t\tname: typeof name === 'string' ? name : undefined,\n\t\t\temailVerified,\n\t\t\t...(idpSession ? { idpSession } : {}),\n\t\t}\n\t} catch (e: any) {\n\t\tif (e instanceof errors.RPError) {\n\t\t\tthrow new IDPValidationError(e.message)\n\t\t}\n\t\tif (e instanceof errors.OPError) {\n\t\t\tconst body = e.response?.body as any\n\t\t\tif (typeof body === 'object' && typeof body?.error === 'object' && typeof body.error?.message === 'string') {\n\t\t\t\tthrow new IDPResponseError(body.error.message)\n\t\t\t}\n\t\t\tthrow new IDPResponseError(e.message)\n\t\t}\n\t\tthrow e\n\t}\n}\n\n/** OIDC errors that definitively mean \"this session is no longer valid at the IdP\". */\nconst REVOKED_OIDC_ERRORS = new Set(['invalid_grant', 'invalid_token', 'expired_token'])\n\n/**\n * Re-validate a stored OIDC session against the IdP. Returns `revoked` only for definitive\n * IdP responses (invalid/expired grant or inactive introspection). Transient failures\n * (network, IdP down) re-throw so the caller can fail-open and keep the session — IdP\n * downtime must not log everyone out.\n */\nexport const revalidateOIDC = async (\n\tclient: Client,\n\tmethod: 'refresh' | 'userinfo' | 'introspection',\n\tsession: IDPSessionState,\n): Promise<RevalidationResult> => {\n\tconst tokens = session.tokens ?? {}\n\tconst refreshToken = typeof tokens.refresh_token === 'string' ? tokens.refresh_token : undefined\n\tconst accessToken = typeof tokens.access_token === 'string' ? tokens.access_token : undefined\n\ttry {\n\t\tif (method === 'refresh') {\n\t\t\tif (!refreshToken) {\n\t\t\t\treturn { status: 'revoked', reason: 'no_refresh_token' }\n\t\t\t}\n\t\t\tconst tokenSet = await client.refresh(refreshToken)\n\t\t\tlet claims: Record<string, unknown> | undefined\n\t\t\ttry {\n\t\t\t\tclaims = tokenSet.id_token ? tokenSet.claims() : undefined\n\t\t\t} catch {\n\t\t\t\tclaims = undefined\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: 'valid',\n\t\t\t\tclaims,\n\t\t\t\t// carry the stored tokens forward: a non-rotating IdP omits the refresh token here\n\t\t\t\tidpSession: tokenSetToSessionState(tokenSet, session.sessionId, tokens),\n\t\t\t}\n\t\t}\n\t\tif (method === 'userinfo') {\n\t\t\tif (!accessToken) {\n\t\t\t\treturn { status: 'revoked', reason: 'no_access_token' }\n\t\t\t}\n\t\t\tconst userInfo = await client.userinfo(accessToken)\n\t\t\treturn { status: 'valid', claims: userInfo }\n\t\t}\n\t\t// introspection\n\t\tconst token = accessToken ?? refreshToken\n\t\tif (!token) {\n\t\t\treturn { status: 'revoked', reason: 'no_token' }\n\t\t}\n\t\tconst result = await client.introspect(token, accessToken ? 'access_token' : 'refresh_token')\n\t\tif (!result.active) {\n\t\t\treturn { status: 'revoked', reason: 'inactive' }\n\t\t}\n\t\treturn { status: 'valid' }\n\t} catch (e: any) {\n\t\tif (e instanceof errors.OPError) {\n\t\t\tif (typeof e.error === 'string' && REVOKED_OIDC_ERRORS.has(e.error)) {\n\t\t\t\treturn { status: 'revoked', reason: e.error }\n\t\t\t}\n\t\t\t// The userinfo endpoint signals a rejected access token with a bare HTTP 401 — per\n\t\t\t// RFC 6750 the `WWW-Authenticate` error code is optional, so openid-client may not\n\t\t\t// surface a parseable `error` here. A 401 is still definitive: the token is no\n\t\t\t// longer accepted → revoked. (Introspection is NOT treated this way: it returns 200\n\t\t\t// `{active:false}` for revoked tokens, so a 401/400 there means client-auth/config\n\t\t\t// failure — transient, must not log users out.)\n\t\t\tif (method === 'userinfo' && e.response?.statusCode === 401) {\n\t\t\t\treturn { status: 'revoked', reason: 'userinfo_unauthorized' }\n\t\t\t}\n\t\t}\n\t\t// transient (network / IdP unavailable) — propagate, do not revoke\n\t\tthrow e\n\t}\n}\n\n/**\n * Build an RP-initiated (front-channel) logout URL (OIDC RP-Initiated Logout 1.0). Returns null\n * when the IdP advertises no `end_session_endpoint` — the caller then degrades to a local-only\n * logout (legacy-IdP graceful fallback). The `id_token_hint` lets the IdP identify and confirm the\n * session to terminate; `post_logout_redirect_uri` is where the IdP returns the browser afterwards.\n */\nexport const buildOIDCLogoutUrl = (client: Client, { idToken, postLogoutRedirectUri }: LogoutUrlRequest): string | null => {\n\tif (!client.issuer.metadata.end_session_endpoint) {\n\t\treturn null\n\t}\n\treturn client.endSessionUrl({\n\t\t...(idToken ? { id_token_hint: idToken } : {}),\n\t\t...(postLogoutRedirectUri ? { post_logout_redirect_uri: postLogoutRedirectUri } : {}),\n\t})\n}\n\n/**\n * The OIDC Back-Channel Logout 1.0 event member that MUST be present in a logout token's `events`\n * claim. Its presence (and the absence of a `nonce`) is what distinguishes a logout token from an\n * ID token — both are signed by the same IdP, so without this check an ID token could be replayed\n * to forcibly log a user out.\n */\nconst BACKCHANNEL_LOGOUT_EVENT = 'http://schemas.openid.net/event/backchannel-logout'\n\n/**\n * Max accepted age of a back-channel logout token, derived from its `iat`. OIDC Back-Channel Logout\n * tokens are single-use and short-lived; bounding the age (together with requiring `exp`) limits the\n * window in which a captured token could be replayed to force a logout.\n */\nconst LOGOUT_TOKEN_MAX_AGE_SECONDS = 120\nconst LOGOUT_TOKEN_CLOCK_TOLERANCE_SECONDS = 5\n\n/**\n * Remote JWKS sets keyed by `jwks_uri`. `createRemoteJWKSet` returns a function with its own internal\n * key cache + fetch cooldown, so it MUST be reused across requests — re-creating it per call (as the\n * unauthenticated back-channel endpoint would otherwise do) defeats the cache and turns every request\n * into a potential outbound JWKS fetch. Keyed by URL, so two providers sharing an IdP share the set.\n */\nconst remoteJwksCache = new Map<string, ReturnType<typeof createRemoteJWKSet>>()\n\nconst getRemoteJwks = (jwksUri: string): ReturnType<typeof createRemoteJWKSet> => {\n\tlet jwks = remoteJwksCache.get(jwksUri)\n\tif (!jwks) {\n\t\tjwks = createRemoteJWKSet(new URL(jwksUri))\n\t\tremoteJwksCache.set(jwksUri, jwks)\n\t}\n\treturn jwks\n}\n\n/**\n * Validate an OIDC back-channel logout token (OIDC Back-Channel Logout 1.0 §2.4–2.6) and extract\n * the targeted `sid` / `sub`. The token is a JWT signed by the IdP; we verify the signature against\n * the issuer's JWKS and enforce the issuer + audience (client_id) the same way ID tokens are\n * verified, pinning the signing algorithm to the provider's configured one, then assert the\n * back-channel-specific claims:\n * - `iat` is present and recent and `exp` is present (§2.4 requires both) — bounds the replay window;\n * - `events` contains the back-channel-logout member (it really is a logout token);\n * - it carries a `sid` and/or `sub` (otherwise there is nothing to act on);\n * - it does NOT carry a `nonce` (a `nonce` means it is an ID token being replayed).\n * Throws {@link IDPValidationError} on any failure so the caller can answer 400.\n */\nexport const validateOIDCLogoutToken = async (client: Client, issuer: Issuer<Client>, logoutToken: string): Promise<LogoutTokenClaims> => {\n\tconst jwksUri = issuer.metadata.jwks_uri\n\tif (!jwksUri) {\n\t\tthrow new IDPValidationError('IdP has no jwks_uri; cannot verify logout token')\n\t}\n\tconst clientId = client.metadata.client_id\n\tif (typeof clientId !== 'string' || clientId === '') {\n\t\t// The `aud` check is a core anti-token-substitution defence on this unauthenticated endpoint.\n\t\t// jose treats `audience: undefined` as \"skip the aud check entirely\", so a missing client_id\n\t\t// must fail closed (reject the token) rather than fall through and accept any audience.\n\t\tthrow new IDPValidationError('cannot verify logout token audience: client_id is missing')\n\t}\n\tconst expectedAlg = typeof client.metadata.id_token_signed_response_alg === 'string'\n\t\t? client.metadata.id_token_signed_response_alg\n\t\t: 'RS256'\n\tconst jwks = getRemoteJwks(jwksUri)\n\tlet payload: Record<string, unknown>\n\ttry {\n\t\tconst verified = await jwtVerify(logoutToken, jwks, {\n\t\t\tissuer: issuer.metadata.issuer,\n\t\t\taudience: clientId,\n\t\t\t// pin to the provider's configured signing alg so a JWKS containing a symmetric/none key\n\t\t\t// can never be selected (defence-in-depth on top of jose's own key-type check).\n\t\t\talgorithms: [expectedAlg],\n\t\t\t// §2.4: `iat` and `exp` are REQUIRED. `maxTokenAge` makes `iat` required + bounds freshness;\n\t\t\t// `requiredClaims` makes `exp` required (jose only checks `exp` when present).\n\t\t\tmaxTokenAge: LOGOUT_TOKEN_MAX_AGE_SECONDS,\n\t\t\trequiredClaims: ['exp'],\n\t\t\tclockTolerance: LOGOUT_TOKEN_CLOCK_TOLERANCE_SECONDS,\n\t\t})\n\t\tpayload = verified.payload as Record<string, unknown>\n\t} catch (e: any) {\n\t\tthrow new IDPValidationError(`Invalid logout token: ${e?.message ?? 'verification failed'}`)\n\t}\n\n\t// A logout token MUST NOT contain a nonce; its presence means an ID token is being replayed.\n\tif ('nonce' in payload) {\n\t\tthrow new IDPValidationError('Logout token must not contain a nonce')\n\t}\n\n\tconst events = payload.events\n\tconst hasLogoutEvent = typeof events === 'object' && events !== null && BACKCHANNEL_LOGOUT_EVENT in (events as Record<string, unknown>)\n\tif (!hasLogoutEvent) {\n\t\tthrow new IDPValidationError('Logout token is missing the back-channel-logout event')\n\t}\n\n\tconst sid = typeof payload.sid === 'string' ? payload.sid : undefined\n\tconst sub = typeof payload.sub === 'string' ? payload.sub : undefined\n\tif (!sid && !sub) {\n\t\tthrow new IDPValidationError('Logout token must contain a sid or sub claim')\n\t}\n\n\treturn { sid, sub }\n}\n"],"names":["generators","IDPValidationError","errors","IDPResponseError","createRemoteJWKSet","jwtVerify"],"mappings":"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"}
1
+ {"version":3,"file":"OIDCHelpers.cjs","sources":["../../../../../../../../packages/engine-tenant-api/src/model/service/idp/providers/OIDCHelpers.ts"],"sourcesContent":["import { Client, custom, errors, generators, Issuer, TokenSet } from 'openid-client'\nimport { createRemoteJWKSet, jwtVerify } from 'jose'\nimport { OIDCClaimMapping, OIDCResponseData } from './OIDCTypes.js'\nimport { IDPValidationError } from '../IDPValidationError.js'\nimport { IDPResponseError } from '../IDPResponseError.js'\nimport {\n\tIDPResponse,\n\tIDPSessionState,\n\tInitIDPAuthResult,\n\tLogoutTokenClaims,\n\tLogoutUrlRequest,\n\tRevalidationResult,\n} from '../IdentityProviderHandler.js'\n\n/**\n * Build the persisted session state from an OIDC token set. Stores the tokens needed for\n * later re-validation (refresh/access) and SLO (id_token); the whole `tokens` blob is\n * encrypted at rest by the command layer.\n *\n * `prevTokens` carries the previously stored tokens forward: a refresh-grant response MAY omit\n * the refresh token (RFC 6749 §6 — IdPs that don't rotate just don't re-send it), in which case\n * the client must keep using the old one. Without this fallback a non-rotating IdP would persist\n * a session with no refresh token and be revoked (`no_refresh_token`) on the very next tick.\n */\nexport const tokenSetToSessionState = (tokenSet: TokenSet, sessionId?: string, prevTokens?: Record<string, unknown>): IDPSessionState => {\n\tconst refreshToken = tokenSet.refresh_token ?? (typeof prevTokens?.refresh_token === 'string' ? prevTokens.refresh_token : undefined)\n\tconst idToken = tokenSet.id_token ?? (typeof prevTokens?.id_token === 'string' ? prevTokens.id_token : undefined)\n\treturn {\n\t\tsessionId,\n\t\ttokens: {\n\t\t\t...(refreshToken ? { refresh_token: refreshToken } : {}),\n\t\t\t...(tokenSet.access_token ? { access_token: tokenSet.access_token } : {}),\n\t\t\t...(idToken ? { id_token: idToken } : {}),\n\t\t},\n\t\texpiresAt: tokenSet.expires_at ? new Date(tokenSet.expires_at * 1000) : undefined,\n\t}\n}\n\nexport const initOIDCAuth = async (\n\tclient: Client,\n\t{ redirectUrl, scope, responseMode }: { redirectUrl: string; scope?: string; responseMode?: string },\n): Promise<InitIDPAuthResult> => {\n\tconst nonce = generators.nonce()\n\tconst state = generators.state()\n\tconst url = client.authorizationUrl({\n\t\tredirect_uri: redirectUrl,\n\t\tresponse_mode: responseMode,\n\t\tscope: scope ?? 'openid email',\n\t\tnonce,\n\t\tstate,\n\t})\n\n\treturn {\n\t\tauthUrl: url,\n\t\tsessionData: { nonce, state },\n\t}\n}\n\nexport type HandleOIDCResponseOptions = {\n\tfetchUserInfo?: boolean\n\treturnOIDCResult?: boolean\n\tcaptureSession?: boolean\n\tclaimMapping?: OIDCClaimMapping\n}\n\n/**\n * Read a claim by name, supporting dot-paths into nested objects (`a.b.c`). Own-property only at every\n * segment (mirrors `ClaimMappingEvaluator.resolvePath`): a configured path must never descend into an\n * inherited member, so a `__proto__` / `constructor` segment cannot surface an `Object.prototype` value\n * as the externalIdentifier / email / name.\n */\nconst getClaim = (source: Record<string, unknown>, path: string): unknown =>\n\tpath.split('.').reduce<unknown>(\n\t\t(\n\t\t\tacc,\n\t\t\tkey,\n\t\t) => (acc != null && typeof acc === 'object' && Object.prototype.hasOwnProperty.call(acc, key) ? (acc as Record<string, unknown>)[key] : undefined),\n\t\tsource,\n\t)\n\n/**\n * Lift a configured nested attributes object (`attributesKey`, notably Apereo CAS's `attributes`) to the\n * top level so providers that nest their claims map without a code change. The nested attributes are\n * UNSIGNED, so they are spread UNDER `source` — a signed top-level claim keeps precedence over an\n * attributes-level value. Shared by the sign-in response handler ({@link handleOIDCResponse}) and the\n * session-refresh path ({@link revalidateOIDC}) so BOTH see the same claim surface; without this, an\n * `attributesKey` provider's A09 claim mapping would resolve at sign-in but silently not on refresh.\n */\nexport const liftNestedClaims = (source: Record<string, unknown>, attributesKey: string | undefined): Record<string, unknown> => {\n\tif (!attributesKey) {\n\t\treturn source\n\t}\n\tconst nested = Object.prototype.hasOwnProperty.call(source, attributesKey) ? source[attributesKey] : undefined\n\tif (nested !== null && typeof nested === 'object' && !Array.isArray(nested)) {\n\t\treturn { ...nested, ...source }\n\t}\n\treturn source\n}\n\ntype NormalizedClaims = Record<string, unknown> & {\n\texternalIdentifier: string\n\temail: string | undefined\n\tname: string | undefined\n\temailVerified: boolean\n}\n\n/**\n * Build the normalized claim surface shared by sign-in ({@link handleOIDCResponse}) and session refresh\n * ({@link revalidateOIDC}): lift any configured nested attributes object to the top level, then layer the\n * mapped identity fields (`externalIdentifier` / `email` / `name` / `emailVerified`) over the raw claims.\n * BOTH paths run this SAME normalization so an A09 claim-mapping rule resolves identically whether it\n * targets a raw provider claim or one of the normalized identity fields — without it the two surfaces\n * diverged (refresh saw the raw claim, sign-in the mapped value).\n *\n * `subFallback` is the signature-verified ID-token `sub`, used when a custom `externalIdentifier` mapping\n * resolves to nothing: at sign-in it is guaranteed present; on refresh it is the refreshed id-token's `sub`\n * (or, for the userinfo method, the userinfo `sub`). Throws (account-takeover guard) when the mapped\n * subject is a non-scalar or resolves empty — the refresh caller catches this and skips the sync.\n */\nconst normalizeClaims = (\n\trawSource: Record<string, unknown>,\n\tclaimMapping: OIDCClaimMapping | undefined,\n\tsubFallback: string | undefined,\n): NormalizedClaims => {\n\tconst source = liftNestedClaims(rawSource, claimMapping?.attributesKey)\n\n\t// The OIDC `email_verified` claim is a boolean per spec, but some providers send the\n\t// string \"true\". userInfo (and any unwrapped attributes) take precedence over the ID token.\n\tconst rawEmailVerified = source.email_verified\n\tconst emailVerified = rawEmailVerified === true || rawEmailVerified === 'true'\n\n\t// `externalIdentifier` is the federation key persisted in `person_identity_provider` and\n\t// matched on the next sign-in, so it must be a stable scalar. A `claimMapping` that pointed\n\t// it at an object/array would otherwise be coerced by `String(...)` to `'[object Object]'` /\n\t// a comma-join — collapsing every user of the provider onto one key (account takeover). Fail\n\t// closed instead. The default `sub` path is safe (openid-client guarantees `sub` is a string).\n\tconst mappedSubject = getClaim(source, claimMapping?.externalIdentifier ?? 'sub')\n\tlet externalIdentifier: string\n\tif (mappedSubject === undefined || mappedSubject === null) {\n\t\texternalIdentifier = subFallback ?? ''\n\t} else if (typeof mappedSubject === 'string' || typeof mappedSubject === 'number') {\n\t\texternalIdentifier = String(mappedSubject)\n\t} else {\n\t\tthrow new IDPValidationError(`The mapped externalIdentifier claim is not a scalar value`)\n\t}\n\tif (externalIdentifier === '') {\n\t\tthrow new IDPValidationError(`The mapped externalIdentifier claim resolved to an empty value`)\n\t}\n\n\t// `email` / `name` are typed `string | undefined` on IDPResponse and feed the by-e-mail\n\t// account lookup (which crashes on a non-string). `...source` already placed the raw claim\n\t// of whatever type, so OVERWRITE (don't conditionally add) with the mapped value when it is\n\t// a string, otherwise `undefined` — a non-string claim must not leak through `...source`.\n\tconst email = getClaim(source, claimMapping?.email ?? 'email')\n\tconst name = resolveName(source, claimMapping)\n\n\treturn {\n\t\t...source,\n\t\texternalIdentifier,\n\t\temail: typeof email === 'string' ? email : undefined,\n\t\tname,\n\t\temailVerified,\n\t}\n}\n\n/**\n * Resolve the display name, falling back to `given_name` + `family_name` when there is no usable\n * `name` claim.\n *\n * `name` is optional in OIDC core and plenty of providers omit it while sending the parts — Apereo\n * CAS and Entra ID do, and so does Keycloak under its default mappers. Without the fallback,\n * `CreatePersonCommand` lands on its own last-resort default and a federated person ends up named\n * after the local part of their e-mail (`jan.novak`) despite the IdP having reported \"Jan Novák\".\n * A single-path `claimMapping.name` cannot express this: the value has to be composed from two\n * claims, not selected from one.\n *\n * An explicitly configured `claimMapping.name` is honoured as-is, fallback included — mapping a\n * claim is a statement about where the name lives, and quietly substituting a different source\n * would defeat it. A blank claim counts as absent: an empty string is not a display name, and\n * treating it as one would keep the fallback (and `CreatePersonCommand`'s) from ever running.\n */\nconst resolveName = (source: Record<string, unknown>, claimMapping: OIDCClaimMapping | undefined): string | undefined => {\n\tconst mapped = getClaim(source, claimMapping?.name ?? 'name')\n\tif (typeof mapped === 'string' && mapped.trim() !== '') {\n\t\treturn mapped\n\t}\n\tif (claimMapping?.name !== undefined) {\n\t\treturn undefined\n\t}\n\tconst parts = [getClaim(source, 'given_name'), getClaim(source, 'family_name')]\n\t\t.filter((part): part is string => typeof part === 'string' && part.trim() !== '')\n\t\t.map(part => part.trim())\n\treturn parts.length > 0 ? parts.join(' ') : undefined\n}\n\nexport const handleOIDCResponse = async (\n\tclient: Client,\n\t{ sessionData, redirectUrl, ...otherData }: OIDCResponseData,\n\t{ fetchUserInfo, returnOIDCResult, captureSession, claimMapping }: HandleOIDCResponseOptions = {},\n): Promise<IDPResponse> => {\n\tconst params = 'parameters' in otherData ? otherData.parameters : client.callbackParams(otherData.url)\n\tif (params.state && !sessionData?.state) {\n\t\tthrow new IDPValidationError(`state is present in parameters, but missing in session data`)\n\t}\n\ttry {\n\t\tconst result = await client.callback(redirectUrl, params, sessionData)\n\t\tconst claims = result.claims()\n\t\tconst { at_hash, c_hash, nonce, ...claimsWithoutHashes } = claims\n\t\tconst userInfo = result.access_token && fetchUserInfo ? await client.userinfo(result) : {}\n\t\tconst oidcResult = returnOIDCResult ? result : {}\n\t\tconst idpSession = captureSession ? tokenSetToSessionState(result, typeof claims.sid === 'string' ? claims.sid : undefined) : undefined\n\n\t\t// Merge ID-token claims with userInfo (userInfo wins, per spec), then normalize the surface (lift\n\t\t// nested attributes + map the identity fields). The refresh path runs the SAME normalization, so a\n\t\t// claim mapping resolves identically at sign-in and on refresh. The default `sub` fallback is safe —\n\t\t// openid-client guarantees `sub` is a string.\n\t\tconst normalized = normalizeClaims({ ...claimsWithoutHashes, ...userInfo }, claimMapping, claims.sub)\n\n\t\treturn {\n\t\t\t...oidcResult,\n\t\t\t...normalized,\n\t\t\t...(idpSession ? { idpSession } : {}),\n\t\t}\n\t} catch (e: any) {\n\t\tif (e instanceof errors.RPError) {\n\t\t\tthrow new IDPValidationError(e.message)\n\t\t}\n\t\tif (e instanceof errors.OPError) {\n\t\t\tconst body = e.response?.body as any\n\t\t\tif (typeof body === 'object' && typeof body?.error === 'object' && typeof body.error?.message === 'string') {\n\t\t\t\tthrow new IDPResponseError(body.error.message)\n\t\t\t}\n\t\t\tthrow new IDPResponseError(e.message)\n\t\t}\n\t\tthrow e\n\t}\n}\n\n/** OIDC errors that definitively mean \"this session is no longer valid at the IdP\". */\nconst REVOKED_OIDC_ERRORS = new Set(['invalid_grant', 'invalid_token', 'expired_token'])\n\n/**\n * Re-validate a stored OIDC session against the IdP. Returns `revoked` only for definitive\n * IdP responses (invalid/expired grant or inactive introspection). Transient failures\n * (network, IdP down) re-throw so the caller can fail-open and keep the session — IdP\n * downtime must not log everyone out.\n */\nexport const revalidateOIDC = async (\n\tclient: Client,\n\tmethod: 'refresh' | 'userinfo' | 'introspection',\n\tsession: IDPSessionState,\n\toptions: { claimMapping?: OIDCClaimMapping; fetchUserInfo?: boolean } = {},\n): Promise<RevalidationResult> => {\n\tconst { claimMapping, fetchUserInfo } = options\n\tconst tokens = session.tokens ?? {}\n\tconst refreshToken = typeof tokens.refresh_token === 'string' ? tokens.refresh_token : undefined\n\tconst accessToken = typeof tokens.access_token === 'string' ? tokens.access_token : undefined\n\ttry {\n\t\tif (method === 'refresh') {\n\t\t\tif (!refreshToken) {\n\t\t\t\treturn { status: 'revoked', reason: 'no_refresh_token' }\n\t\t\t}\n\t\t\tconst tokenSet = await client.refresh(refreshToken)\n\t\t\tlet claims: Record<string, unknown> | undefined\n\t\t\tlet claimsComplete = false\n\t\t\ttry {\n\t\t\t\t// Reconstruct the SAME claim surface sign-in builds (handleOIDCResponse): the refreshed id-token\n\t\t\t\t// claims merged with userInfo when `fetchUserInfo` is set — exactly as at sign-in — then the shared\n\t\t\t\t// normalization (lift nested attributes + map identity fields). An `always` mapping therefore\n\t\t\t\t// reconciles against an identical surface on refresh, so `claimsComplete` lets the caller enable\n\t\t\t\t// `unmatched: \"remove\"` reconciliation here too (see IdpSessionRevalidator).\n\t\t\t\tif (tokenSet.id_token) {\n\t\t\t\t\tconst idClaims = tokenSet.claims()\n\t\t\t\t\tconst userInfo = tokenSet.access_token && fetchUserInfo ? await client.userinfo(tokenSet) : {}\n\t\t\t\t\tclaims = normalizeClaims({ ...idClaims, ...userInfo }, claimMapping, typeof idClaims.sub === 'string' ? idClaims.sub : undefined)\n\t\t\t\t\tclaimsComplete = true\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Building the surface failed (userinfo unreachable, a non-scalar `externalIdentifier`, …). The IdP\n\t\t\t\t// already vouched for the session via the successful refresh, so KEEP it — just skip the claim sync\n\t\t\t\t// this tick (no claims → no grant, no removal) and retry on a later refresh. Leaving claimsComplete\n\t\t\t\t// false also guarantees a half-built surface can never drive a removal.\n\t\t\t\tclaims = undefined\n\t\t\t\tclaimsComplete = false\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: 'valid',\n\t\t\t\tclaims,\n\t\t\t\tclaimsComplete,\n\t\t\t\t// carry the stored tokens forward: a non-rotating IdP omits the refresh token here\n\t\t\t\tidpSession: tokenSetToSessionState(tokenSet, session.sessionId, tokens),\n\t\t\t}\n\t\t}\n\t\tif (method === 'userinfo') {\n\t\t\tif (!accessToken) {\n\t\t\t\treturn { status: 'revoked', reason: 'no_access_token' }\n\t\t\t}\n\t\t\tconst userInfo = await client.userinfo(accessToken)\n\t\t\tlet claims: Record<string, unknown> | undefined\n\t\t\ttry {\n\t\t\t\tclaims = normalizeClaims(userInfo, claimMapping, typeof userInfo.sub === 'string' ? userInfo.sub : undefined)\n\t\t\t} catch {\n\t\t\t\tclaims = undefined\n\t\t\t}\n\t\t\t// A userinfo probe carries no id-token claims, so its surface is NARROWER than sign-in's (id-token +\n\t\t\t// userinfo): a rule keyed on an id-token-only claim would miss here. Keep refresh-time sync additive-only\n\t\t\t// (`claimsComplete: false`) so `unmatched: \"remove\"` never strips a membership off this partial surface.\n\t\t\treturn { status: 'valid', claims, claimsComplete: false }\n\t\t}\n\t\t// introspection\n\t\tconst token = accessToken ?? refreshToken\n\t\tif (!token) {\n\t\t\treturn { status: 'revoked', reason: 'no_token' }\n\t\t}\n\t\tconst result = await client.introspect(token, accessToken ? 'access_token' : 'refresh_token')\n\t\tif (!result.active) {\n\t\t\treturn { status: 'revoked', reason: 'inactive' }\n\t\t}\n\t\treturn { status: 'valid' }\n\t} catch (e: any) {\n\t\tif (e instanceof errors.OPError) {\n\t\t\tif (typeof e.error === 'string' && REVOKED_OIDC_ERRORS.has(e.error)) {\n\t\t\t\treturn { status: 'revoked', reason: e.error }\n\t\t\t}\n\t\t\t// The userinfo endpoint signals a rejected access token with a bare HTTP 401 — per\n\t\t\t// RFC 6750 the `WWW-Authenticate` error code is optional, so openid-client may not\n\t\t\t// surface a parseable `error` here. A 401 is still definitive: the token is no\n\t\t\t// longer accepted → revoked. (Introspection is NOT treated this way: it returns 200\n\t\t\t// `{active:false}` for revoked tokens, so a 401/400 there means client-auth/config\n\t\t\t// failure — transient, must not log users out.)\n\t\t\tif (method === 'userinfo' && e.response?.statusCode === 401) {\n\t\t\t\treturn { status: 'revoked', reason: 'userinfo_unauthorized' }\n\t\t\t}\n\t\t}\n\t\t// transient (network / IdP unavailable) — propagate, do not revoke\n\t\tthrow e\n\t}\n}\n\n/**\n * Build an RP-initiated (front-channel) logout URL (OIDC RP-Initiated Logout 1.0). Returns null\n * when the IdP advertises no `end_session_endpoint` — the caller then degrades to a local-only\n * logout (legacy-IdP graceful fallback). The `id_token_hint` lets the IdP identify and confirm the\n * session to terminate; `post_logout_redirect_uri` is where the IdP returns the browser afterwards.\n */\nexport const buildOIDCLogoutUrl = (client: Client, { idToken, postLogoutRedirectUri }: LogoutUrlRequest): string | null => {\n\tif (!client.issuer.metadata.end_session_endpoint) {\n\t\treturn null\n\t}\n\treturn client.endSessionUrl({\n\t\t...(idToken ? { id_token_hint: idToken } : {}),\n\t\t...(postLogoutRedirectUri ? { post_logout_redirect_uri: postLogoutRedirectUri } : {}),\n\t})\n}\n\n/**\n * The OIDC Back-Channel Logout 1.0 event member that MUST be present in a logout token's `events`\n * claim. Its presence (and the absence of a `nonce`) is what distinguishes a logout token from an\n * ID token — both are signed by the same IdP, so without this check an ID token could be replayed\n * to forcibly log a user out.\n */\nconst BACKCHANNEL_LOGOUT_EVENT = 'http://schemas.openid.net/event/backchannel-logout'\n\n/**\n * Max accepted age of a back-channel logout token, derived from its `iat`. OIDC Back-Channel Logout\n * tokens are single-use and short-lived; bounding the age (together with requiring `exp`) limits the\n * window in which a captured token could be replayed to force a logout.\n */\nconst LOGOUT_TOKEN_MAX_AGE_SECONDS = 120\nconst LOGOUT_TOKEN_CLOCK_TOLERANCE_SECONDS = 5\n\n/**\n * Remote JWKS sets keyed by `jwks_uri`. `createRemoteJWKSet` returns a function with its own internal\n * key cache + fetch cooldown, so it MUST be reused across requests — re-creating it per call (as the\n * unauthenticated back-channel endpoint would otherwise do) defeats the cache and turns every request\n * into a potential outbound JWKS fetch. Keyed by URL, so two providers sharing an IdP share the set.\n */\nconst remoteJwksCache = new Map<string, ReturnType<typeof createRemoteJWKSet>>()\n\nconst getRemoteJwks = (jwksUri: string): ReturnType<typeof createRemoteJWKSet> => {\n\tlet jwks = remoteJwksCache.get(jwksUri)\n\tif (!jwks) {\n\t\tjwks = createRemoteJWKSet(new URL(jwksUri))\n\t\tremoteJwksCache.set(jwksUri, jwks)\n\t}\n\treturn jwks\n}\n\n/**\n * Validate an OIDC back-channel logout token (OIDC Back-Channel Logout 1.0 §2.4–2.6) and extract\n * the targeted `sid` / `sub`. The token is a JWT signed by the IdP; we verify the signature against\n * the issuer's JWKS and enforce the issuer + audience (client_id) the same way ID tokens are\n * verified, pinning the signing algorithm to the provider's configured one, then assert the\n * back-channel-specific claims:\n * - `iat` is present and recent and `exp` is present (§2.4 requires both) — bounds the replay window;\n * - `events` contains the back-channel-logout member (it really is a logout token);\n * - it carries a `sid` and/or `sub` (otherwise there is nothing to act on);\n * - it does NOT carry a `nonce` (a `nonce` means it is an ID token being replayed).\n * Throws {@link IDPValidationError} on any failure so the caller can answer 400.\n */\nexport const validateOIDCLogoutToken = async (client: Client, issuer: Issuer<Client>, logoutToken: string): Promise<LogoutTokenClaims> => {\n\tconst jwksUri = issuer.metadata.jwks_uri\n\tif (!jwksUri) {\n\t\tthrow new IDPValidationError('IdP has no jwks_uri; cannot verify logout token')\n\t}\n\tconst clientId = client.metadata.client_id\n\tif (typeof clientId !== 'string' || clientId === '') {\n\t\t// The `aud` check is a core anti-token-substitution defence on this unauthenticated endpoint.\n\t\t// jose treats `audience: undefined` as \"skip the aud check entirely\", so a missing client_id\n\t\t// must fail closed (reject the token) rather than fall through and accept any audience.\n\t\tthrow new IDPValidationError('cannot verify logout token audience: client_id is missing')\n\t}\n\tconst expectedAlg = typeof client.metadata.id_token_signed_response_alg === 'string'\n\t\t? client.metadata.id_token_signed_response_alg\n\t\t: 'RS256'\n\tconst jwks = getRemoteJwks(jwksUri)\n\tlet payload: Record<string, unknown>\n\ttry {\n\t\tconst verified = await jwtVerify(logoutToken, jwks, {\n\t\t\tissuer: issuer.metadata.issuer,\n\t\t\taudience: clientId,\n\t\t\t// pin to the provider's configured signing alg so a JWKS containing a symmetric/none key\n\t\t\t// can never be selected (defence-in-depth on top of jose's own key-type check).\n\t\t\talgorithms: [expectedAlg],\n\t\t\t// §2.4: `iat` and `exp` are REQUIRED. `maxTokenAge` makes `iat` required + bounds freshness;\n\t\t\t// `requiredClaims` makes `exp` required (jose only checks `exp` when present).\n\t\t\tmaxTokenAge: LOGOUT_TOKEN_MAX_AGE_SECONDS,\n\t\t\trequiredClaims: ['exp'],\n\t\t\tclockTolerance: LOGOUT_TOKEN_CLOCK_TOLERANCE_SECONDS,\n\t\t})\n\t\tpayload = verified.payload as Record<string, unknown>\n\t} catch (e: any) {\n\t\tthrow new IDPValidationError(`Invalid logout token: ${e?.message ?? 'verification failed'}`)\n\t}\n\n\t// A logout token MUST NOT contain a nonce; its presence means an ID token is being replayed.\n\tif ('nonce' in payload) {\n\t\tthrow new IDPValidationError('Logout token must not contain a nonce')\n\t}\n\n\tconst events = payload.events\n\tconst hasLogoutEvent = typeof events === 'object' && events !== null && BACKCHANNEL_LOGOUT_EVENT in (events as Record<string, unknown>)\n\tif (!hasLogoutEvent) {\n\t\tthrow new IDPValidationError('Logout token is missing the back-channel-logout event')\n\t}\n\n\tconst sid = typeof payload.sid === 'string' ? payload.sid : undefined\n\tconst sub = typeof payload.sub === 'string' ? payload.sub : undefined\n\tif (!sid && !sub) {\n\t\tthrow new IDPValidationError('Logout token must contain a sid or sub claim')\n\t}\n\n\treturn { sid, sub }\n}\n"],"names":["generators","IDPValidationError","errors","IDPResponseError","createRemoteJWKSet","jwtVerify"],"mappings":"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"}