@authup/server-core 1.0.0-beta.50 → 1.0.0-beta.52

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 (656) hide show
  1. package/dist/adapters/database/data-source/options/module.d.ts.map +1 -1
  2. package/dist/adapters/database/data-source/options/module.mjs +2 -0
  3. package/dist/adapters/database/data-source/options/module.mjs.map +1 -1
  4. package/dist/adapters/database/domains/client/entity.d.ts +1 -0
  5. package/dist/adapters/database/domains/client/entity.d.ts.map +1 -1
  6. package/dist/adapters/database/domains/client/entity.mjs +5 -0
  7. package/dist/adapters/database/domains/client/entity.mjs.map +1 -1
  8. package/dist/adapters/database/domains/client-permission/entity.d.ts +2 -1
  9. package/dist/adapters/database/domains/client-permission/entity.d.ts.map +1 -1
  10. package/dist/adapters/database/domains/client-permission/entity.mjs +6 -0
  11. package/dist/adapters/database/domains/client-permission/entity.mjs.map +1 -1
  12. package/dist/adapters/database/domains/index.d.ts +1 -0
  13. package/dist/adapters/database/domains/index.d.ts.map +1 -1
  14. package/dist/adapters/database/domains/index.mjs +3 -1
  15. package/dist/adapters/database/domains/robot-permission/entity.d.ts +2 -1
  16. package/dist/adapters/database/domains/robot-permission/entity.d.ts.map +1 -1
  17. package/dist/adapters/database/domains/robot-permission/entity.mjs +6 -0
  18. package/dist/adapters/database/domains/robot-permission/entity.mjs.map +1 -1
  19. package/dist/adapters/database/domains/robot-role/entity.mjs +1 -1
  20. package/dist/adapters/database/domains/robot-role/entity.mjs.map +1 -1
  21. package/dist/adapters/database/domains/role-permission/entity.d.ts +2 -1
  22. package/dist/adapters/database/domains/role-permission/entity.d.ts.map +1 -1
  23. package/dist/adapters/database/domains/role-permission/entity.mjs +6 -0
  24. package/dist/adapters/database/domains/role-permission/entity.mjs.map +1 -1
  25. package/dist/adapters/database/domains/session/entity.mjs +1 -1
  26. package/dist/adapters/database/domains/session/entity.mjs.map +1 -1
  27. package/dist/adapters/database/domains/session-token/entity.d.ts +17 -0
  28. package/dist/adapters/database/domains/session-token/entity.d.ts.map +1 -0
  29. package/dist/adapters/database/domains/session-token/entity.mjs +95 -0
  30. package/dist/adapters/database/domains/session-token/entity.mjs.map +1 -0
  31. package/dist/adapters/database/domains/session-token/index.d.ts +2 -0
  32. package/dist/adapters/database/domains/session-token/index.d.ts.map +1 -0
  33. package/dist/adapters/database/domains/session-token/index.mjs +5 -0
  34. package/dist/adapters/database/domains/user-permission/entity.d.ts +2 -1
  35. package/dist/adapters/database/domains/user-permission/entity.d.ts.map +1 -1
  36. package/dist/adapters/database/domains/user-permission/entity.mjs +6 -0
  37. package/dist/adapters/database/domains/user-permission/entity.mjs.map +1 -1
  38. package/dist/adapters/database/index.mjs +2 -1
  39. package/dist/adapters/database/migrations/mysql/1779300000000-Default.d.ts +7 -0
  40. package/dist/adapters/database/migrations/mysql/1779300000000-Default.d.ts.map +1 -0
  41. package/dist/adapters/database/migrations/mysql/1779300000000-Default.mjs +85 -0
  42. package/dist/adapters/database/migrations/mysql/1779300000000-Default.mjs.map +1 -0
  43. package/dist/adapters/database/migrations/mysql/1783325495597-Default.d.ts +28 -0
  44. package/dist/adapters/database/migrations/mysql/1783325495597-Default.d.ts.map +1 -0
  45. package/dist/adapters/database/migrations/mysql/1783325495597-Default.mjs +85 -0
  46. package/dist/adapters/database/migrations/mysql/1783325495597-Default.mjs.map +1 -0
  47. package/dist/adapters/database/migrations/postgres/1779300000000-Default.d.ts +7 -0
  48. package/dist/adapters/database/migrations/postgres/1779300000000-Default.d.ts.map +1 -0
  49. package/dist/adapters/database/migrations/postgres/1779300000000-Default.mjs +87 -0
  50. package/dist/adapters/database/migrations/postgres/1779300000000-Default.mjs.map +1 -0
  51. package/dist/adapters/database/migrations/postgres/1783325495597-Default.d.ts +28 -0
  52. package/dist/adapters/database/migrations/postgres/1783325495597-Default.d.ts.map +1 -0
  53. package/dist/adapters/database/migrations/postgres/1783325495597-Default.mjs +79 -0
  54. package/dist/adapters/database/migrations/postgres/1783325495597-Default.mjs.map +1 -0
  55. package/dist/adapters/database/subscriber/module.d.ts.map +1 -1
  56. package/dist/adapters/database/subscriber/module.mjs +4 -3
  57. package/dist/adapters/database/subscriber/module.mjs.map +1 -1
  58. package/dist/adapters/http/adapters/index.mjs +3 -2
  59. package/dist/adapters/http/adapters/oauth2/authorization/module.mjs +2 -1
  60. package/dist/adapters/http/adapters/oauth2/authorization/module.mjs.map +1 -1
  61. package/dist/adapters/http/adapters/oauth2/grant-types/authorize.d.ts +2 -1
  62. package/dist/adapters/http/adapters/oauth2/grant-types/authorize.d.ts.map +1 -1
  63. package/dist/adapters/http/adapters/oauth2/grant-types/authorize.mjs +10 -4
  64. package/dist/adapters/http/adapters/oauth2/grant-types/authorize.mjs.map +1 -1
  65. package/dist/adapters/http/adapters/oauth2/grant-types/client-credentials.d.ts.map +1 -1
  66. package/dist/adapters/http/adapters/oauth2/grant-types/client-credentials.mjs +3 -0
  67. package/dist/adapters/http/adapters/oauth2/grant-types/client-credentials.mjs.map +1 -1
  68. package/dist/adapters/http/adapters/oauth2/grant-types/index.mjs +3 -2
  69. package/dist/adapters/http/adapters/oauth2/grant-types/password.d.ts +2 -1
  70. package/dist/adapters/http/adapters/oauth2/grant-types/password.d.ts.map +1 -1
  71. package/dist/adapters/http/adapters/oauth2/grant-types/password.mjs +14 -4
  72. package/dist/adapters/http/adapters/oauth2/grant-types/password.mjs.map +1 -1
  73. package/dist/adapters/http/adapters/oauth2/grant-types/refresh_token.d.ts +2 -1
  74. package/dist/adapters/http/adapters/oauth2/grant-types/refresh_token.d.ts.map +1 -1
  75. package/dist/adapters/http/adapters/oauth2/grant-types/refresh_token.mjs +12 -5
  76. package/dist/adapters/http/adapters/oauth2/grant-types/refresh_token.mjs.map +1 -1
  77. package/dist/adapters/http/adapters/oauth2/grant-types/types.d.ts +4 -1
  78. package/dist/adapters/http/adapters/oauth2/grant-types/types.d.ts.map +1 -1
  79. package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.d.ts +1 -0
  80. package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.d.ts.map +1 -1
  81. package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.mjs +2 -2
  82. package/dist/adapters/http/adapters/oauth2/grant-types/utils/credentials.mjs.map +1 -1
  83. package/dist/adapters/http/adapters/oauth2/grant-types/utils/guess.mjs +1 -1
  84. package/dist/adapters/http/adapters/oauth2/grant-types/utils/index.d.ts +1 -0
  85. package/dist/adapters/http/adapters/oauth2/grant-types/utils/index.d.ts.map +1 -1
  86. package/dist/adapters/http/adapters/oauth2/grant-types/utils/index.mjs +3 -2
  87. package/dist/adapters/http/adapters/oauth2/grant-types/utils/realm.d.ts +9 -0
  88. package/dist/adapters/http/adapters/oauth2/grant-types/utils/realm.d.ts.map +1 -0
  89. package/dist/adapters/http/adapters/oauth2/grant-types/utils/realm.mjs +21 -0
  90. package/dist/adapters/http/adapters/oauth2/grant-types/utils/realm.mjs.map +1 -0
  91. package/dist/adapters/http/adapters/oauth2/index.mjs +3 -2
  92. package/dist/adapters/http/controllers/entities/client/module.mjs +2 -2
  93. package/dist/adapters/http/controllers/entities/client-permission/module.mjs +1 -1
  94. package/dist/adapters/http/controllers/entities/client-role/module.mjs +1 -1
  95. package/dist/adapters/http/controllers/entities/client-scope/module.mjs +1 -1
  96. package/dist/adapters/http/controllers/entities/identity-provide-role/module.mjs +1 -1
  97. package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts.map +1 -1
  98. package/dist/adapters/http/controllers/entities/identity-provider/module.mjs +28 -12
  99. package/dist/adapters/http/controllers/entities/identity-provider/module.mjs.map +1 -1
  100. package/dist/adapters/http/controllers/entities/index.d.ts +1 -0
  101. package/dist/adapters/http/controllers/entities/index.d.ts.map +1 -1
  102. package/dist/adapters/http/controllers/entities/index.mjs +3 -1
  103. package/dist/adapters/http/controllers/entities/permission/module.mjs +1 -1
  104. package/dist/adapters/http/controllers/entities/permission-policy/module.mjs +1 -1
  105. package/dist/adapters/http/controllers/entities/policy/module.mjs +1 -1
  106. package/dist/adapters/http/controllers/entities/realm/module.d.ts.map +1 -1
  107. package/dist/adapters/http/controllers/entities/realm/module.mjs +11 -8
  108. package/dist/adapters/http/controllers/entities/realm/module.mjs.map +1 -1
  109. package/dist/adapters/http/controllers/entities/robot/module.mjs +2 -2
  110. package/dist/adapters/http/controllers/entities/robot-permission/module.mjs +1 -1
  111. package/dist/adapters/http/controllers/entities/robot-role/module.mjs +1 -1
  112. package/dist/adapters/http/controllers/entities/role/module.mjs +1 -1
  113. package/dist/adapters/http/controllers/entities/role-attribute/module.mjs +1 -1
  114. package/dist/adapters/http/controllers/entities/role-permission/module.mjs +1 -1
  115. package/dist/adapters/http/controllers/entities/scope/module.mjs +1 -1
  116. package/dist/adapters/http/controllers/entities/session/index.d.ts +2 -0
  117. package/dist/adapters/http/controllers/entities/session/index.d.ts.map +1 -0
  118. package/dist/adapters/http/controllers/entities/session/index.mjs +5 -0
  119. package/dist/adapters/http/controllers/entities/session/module.d.ts +16 -0
  120. package/dist/adapters/http/controllers/entities/session/module.d.ts.map +1 -0
  121. package/dist/adapters/http/controllers/entities/session/module.mjs +102 -0
  122. package/dist/adapters/http/controllers/entities/session/module.mjs.map +1 -0
  123. package/dist/adapters/http/controllers/entities/user/module.mjs +2 -2
  124. package/dist/adapters/http/controllers/entities/user-attribute/module.mjs +1 -1
  125. package/dist/adapters/http/controllers/entities/user-permission/module.mjs +1 -1
  126. package/dist/adapters/http/controllers/entities/user-role/module.mjs +1 -1
  127. package/dist/adapters/http/controllers/index.mjs +3 -1
  128. package/dist/adapters/http/controllers/workflows/authorize/module.d.ts.map +1 -1
  129. package/dist/adapters/http/controllers/workflows/authorize/module.mjs +22 -9
  130. package/dist/adapters/http/controllers/workflows/authorize/module.mjs.map +1 -1
  131. package/dist/adapters/http/controllers/workflows/authorize/types.d.ts +7 -4
  132. package/dist/adapters/http/controllers/workflows/authorize/types.d.ts.map +1 -1
  133. package/dist/adapters/http/controllers/workflows/index.d.ts +1 -0
  134. package/dist/adapters/http/controllers/workflows/index.d.ts.map +1 -1
  135. package/dist/adapters/http/controllers/workflows/index.mjs +3 -1
  136. package/dist/adapters/http/controllers/workflows/logout/index.d.ts +3 -0
  137. package/dist/adapters/http/controllers/workflows/logout/index.d.ts.map +1 -0
  138. package/dist/adapters/http/controllers/workflows/logout/index.mjs +5 -0
  139. package/dist/adapters/http/controllers/workflows/logout/module.d.ts +14 -0
  140. package/dist/adapters/http/controllers/workflows/logout/module.d.ts.map +1 -0
  141. package/dist/adapters/http/controllers/workflows/logout/module.mjs +101 -0
  142. package/dist/adapters/http/controllers/workflows/logout/module.mjs.map +1 -0
  143. package/dist/adapters/http/controllers/workflows/logout/types.d.ts +9 -0
  144. package/dist/adapters/http/controllers/workflows/logout/types.d.ts.map +1 -0
  145. package/dist/adapters/http/controllers/workflows/logout/types.mjs +4 -0
  146. package/dist/adapters/http/controllers/workflows/status/module.mjs +1 -1
  147. package/dist/adapters/http/controllers/workflows/token/module.d.ts.map +1 -1
  148. package/dist/adapters/http/controllers/workflows/token/module.mjs +12 -4
  149. package/dist/adapters/http/controllers/workflows/token/module.mjs.map +1 -1
  150. package/dist/adapters/http/controllers/workflows/token/types.d.ts +9 -1
  151. package/dist/adapters/http/controllers/workflows/token/types.d.ts.map +1 -1
  152. package/dist/adapters/http/index.mjs +17 -13
  153. package/dist/adapters/http/middleware/built-in/authorization/module.d.ts.map +1 -1
  154. package/dist/adapters/http/middleware/built-in/authorization/module.mjs +2 -0
  155. package/dist/adapters/http/middleware/built-in/authorization/module.mjs.map +1 -1
  156. package/dist/adapters/http/middleware/built-in/index.mjs +2 -2
  157. package/dist/adapters/http/middleware/built-in/logger.d.ts +1 -0
  158. package/dist/adapters/http/middleware/built-in/logger.d.ts.map +1 -1
  159. package/dist/adapters/http/middleware/built-in/logger.mjs +23 -2
  160. package/dist/adapters/http/middleware/built-in/logger.mjs.map +1 -1
  161. package/dist/adapters/http/middleware/built-in/prometheus.d.ts.map +1 -1
  162. package/dist/adapters/http/middleware/built-in/prometheus.mjs +1 -1
  163. package/dist/adapters/http/middleware/built-in/prometheus.mjs.map +1 -1
  164. package/dist/adapters/http/middleware/built-in/realm-resolver/module.d.ts.map +1 -1
  165. package/dist/adapters/http/middleware/built-in/realm-resolver/module.mjs +3 -8
  166. package/dist/adapters/http/middleware/built-in/realm-resolver/module.mjs.map +1 -1
  167. package/dist/adapters/http/middleware/built-in/ui-http-client.d.ts +2 -2
  168. package/dist/adapters/http/middleware/built-in/ui-http-client.mjs +2 -2
  169. package/dist/adapters/http/middleware/built-in/ui-http-client.mjs.map +1 -1
  170. package/dist/adapters/http/middleware/index.mjs +2 -2
  171. package/dist/adapters/http/request/helpers/identity.d.ts +0 -1
  172. package/dist/adapters/http/request/helpers/identity.d.ts.map +1 -1
  173. package/dist/adapters/http/request/helpers/identity.mjs +2 -5
  174. package/dist/adapters/http/request/helpers/identity.mjs.map +1 -1
  175. package/dist/adapters/http/request/helpers/index.d.ts +1 -0
  176. package/dist/adapters/http/request/helpers/index.d.ts.map +1 -1
  177. package/dist/adapters/http/request/helpers/index.mjs +3 -2
  178. package/dist/adapters/http/request/helpers/session-id.d.ts +9 -0
  179. package/dist/adapters/http/request/helpers/session-id.d.ts.map +1 -0
  180. package/dist/adapters/http/request/helpers/session-id.mjs +19 -0
  181. package/dist/adapters/http/request/helpers/session-id.mjs.map +1 -0
  182. package/dist/adapters/http/request/index.mjs +3 -2
  183. package/dist/adapters/http/request/permission/module.d.ts.map +1 -1
  184. package/dist/adapters/http/request/permission/module.mjs +5 -3
  185. package/dist/adapters/http/request/permission/module.mjs.map +1 -1
  186. package/dist/adapters/http/ui/index.d.ts +1 -0
  187. package/dist/adapters/http/ui/index.d.ts.map +1 -1
  188. package/dist/adapters/http/ui/index.mjs +2 -1
  189. package/dist/adapters/http/ui/internal-http-client.d.ts +22 -0
  190. package/dist/adapters/http/ui/internal-http-client.d.ts.map +1 -0
  191. package/dist/adapters/http/ui/internal-http-client.mjs +52 -0
  192. package/dist/adapters/http/ui/internal-http-client.mjs.map +1 -0
  193. package/dist/adapters/http/ui/render.d.ts.map +1 -1
  194. package/dist/adapters/http/ui/render.mjs +5 -2
  195. package/dist/adapters/http/ui/render.mjs.map +1 -1
  196. package/dist/adapters/http/ui/types.d.ts +12 -0
  197. package/dist/adapters/http/ui/types.d.ts.map +1 -1
  198. package/dist/app/modules/authentication/repositories/session.d.ts +5 -2
  199. package/dist/app/modules/authentication/repositories/session.d.ts.map +1 -1
  200. package/dist/app/modules/authentication/repositories/session.mjs +63 -0
  201. package/dist/app/modules/authentication/repositories/session.mjs.map +1 -1
  202. package/dist/app/modules/config/constants.d.ts +4 -0
  203. package/dist/app/modules/config/constants.d.ts.map +1 -1
  204. package/dist/app/modules/config/constants.mjs +4 -0
  205. package/dist/app/modules/config/constants.mjs.map +1 -1
  206. package/dist/app/modules/config/normalize.d.ts.map +1 -1
  207. package/dist/app/modules/config/normalize.mjs +6 -1
  208. package/dist/app/modules/config/normalize.mjs.map +1 -1
  209. package/dist/app/modules/config/read/env.d.ts.map +1 -1
  210. package/dist/app/modules/config/read/env.mjs +8 -0
  211. package/dist/app/modules/config/read/env.mjs.map +1 -1
  212. package/dist/app/modules/config/types.d.ts +31 -2
  213. package/dist/app/modules/config/types.d.ts.map +1 -1
  214. package/dist/app/modules/config/validator.d.ts.map +1 -1
  215. package/dist/app/modules/config/validator.mjs +5 -0
  216. package/dist/app/modules/config/validator.mjs.map +1 -1
  217. package/dist/app/modules/database/module.d.ts +1 -0
  218. package/dist/app/modules/database/module.d.ts.map +1 -1
  219. package/dist/app/modules/database/module.mjs +19 -6
  220. package/dist/app/modules/database/module.mjs.map +1 -1
  221. package/dist/app/modules/database/repositories/bindings.d.ts +2 -0
  222. package/dist/app/modules/database/repositories/bindings.d.ts.map +1 -1
  223. package/dist/app/modules/database/repositories/bindings.mjs +3 -1
  224. package/dist/app/modules/database/repositories/bindings.mjs.map +1 -1
  225. package/dist/app/modules/database/repositories/client/repository.d.ts.map +1 -1
  226. package/dist/app/modules/database/repositories/client/repository.mjs +10 -6
  227. package/dist/app/modules/database/repositories/client/repository.mjs.map +1 -1
  228. package/dist/app/modules/database/repositories/helpers.d.ts +11 -0
  229. package/dist/app/modules/database/repositories/helpers.d.ts.map +1 -1
  230. package/dist/app/modules/database/repositories/helpers.mjs +12 -1
  231. package/dist/app/modules/database/repositories/helpers.mjs.map +1 -1
  232. package/dist/app/modules/database/repositories/identity-provider/repository.d.ts.map +1 -1
  233. package/dist/app/modules/database/repositories/identity-provider/repository.mjs +7 -5
  234. package/dist/app/modules/database/repositories/identity-provider/repository.mjs.map +1 -1
  235. package/dist/app/modules/database/repositories/permission/repository.d.ts.map +1 -1
  236. package/dist/app/modules/database/repositories/permission/repository.mjs +4 -3
  237. package/dist/app/modules/database/repositories/permission/repository.mjs.map +1 -1
  238. package/dist/app/modules/database/repositories/permission-provider/module.d.ts +2 -2
  239. package/dist/app/modules/database/repositories/permission-provider/module.d.ts.map +1 -1
  240. package/dist/app/modules/database/repositories/permission-provider/module.mjs +4 -3
  241. package/dist/app/modules/database/repositories/permission-provider/module.mjs.map +1 -1
  242. package/dist/app/modules/database/repositories/policy/repository.d.ts.map +1 -1
  243. package/dist/app/modules/database/repositories/policy/repository.mjs +4 -3
  244. package/dist/app/modules/database/repositories/policy/repository.mjs.map +1 -1
  245. package/dist/app/modules/database/repositories/realm/repository.d.ts +1 -0
  246. package/dist/app/modules/database/repositories/realm/repository.d.ts.map +1 -1
  247. package/dist/app/modules/database/repositories/realm/repository.mjs +20 -3
  248. package/dist/app/modules/database/repositories/realm/repository.mjs.map +1 -1
  249. package/dist/app/modules/database/repositories/robot/repository.d.ts.map +1 -1
  250. package/dist/app/modules/database/repositories/robot/repository.mjs +8 -6
  251. package/dist/app/modules/database/repositories/robot/repository.mjs.map +1 -1
  252. package/dist/app/modules/database/repositories/role/repository.d.ts.map +1 -1
  253. package/dist/app/modules/database/repositories/role/repository.mjs +4 -3
  254. package/dist/app/modules/database/repositories/role/repository.mjs.map +1 -1
  255. package/dist/app/modules/database/repositories/role-attribute/repository.d.ts.map +1 -1
  256. package/dist/app/modules/database/repositories/role-attribute/repository.mjs +2 -1
  257. package/dist/app/modules/database/repositories/role-attribute/repository.mjs.map +1 -1
  258. package/dist/app/modules/database/repositories/scope/repository.d.ts.map +1 -1
  259. package/dist/app/modules/database/repositories/scope/repository.mjs +4 -3
  260. package/dist/app/modules/database/repositories/scope/repository.mjs.map +1 -1
  261. package/dist/app/modules/database/repositories/user/repository.d.ts.map +1 -1
  262. package/dist/app/modules/database/repositories/user/repository.mjs +8 -5
  263. package/dist/app/modules/database/repositories/user/repository.mjs.map +1 -1
  264. package/dist/app/modules/database/repositories/user-attribute/repository.d.ts.map +1 -1
  265. package/dist/app/modules/database/repositories/user-attribute/repository.mjs +2 -1
  266. package/dist/app/modules/database/repositories/user-attribute/repository.mjs.map +1 -1
  267. package/dist/app/modules/http/constants.d.ts +4 -2
  268. package/dist/app/modules/http/constants.d.ts.map +1 -1
  269. package/dist/app/modules/http/constants.mjs +4 -2
  270. package/dist/app/modules/http/constants.mjs.map +1 -1
  271. package/dist/app/modules/http/module.d.ts +10 -0
  272. package/dist/app/modules/http/module.d.ts.map +1 -1
  273. package/dist/app/modules/http/module.mjs +30 -0
  274. package/dist/app/modules/http/module.mjs.map +1 -1
  275. package/dist/app/modules/http/modules/controller.d.ts +6 -2
  276. package/dist/app/modules/http/modules/controller.d.ts.map +1 -1
  277. package/dist/app/modules/http/modules/controller.mjs +75 -15
  278. package/dist/app/modules/http/modules/controller.mjs.map +1 -1
  279. package/dist/app/modules/http/modules/middleware.mjs +1 -1
  280. package/dist/app/modules/identity/repositories/client.mjs +2 -2
  281. package/dist/app/modules/identity/repositories/client.mjs.map +1 -1
  282. package/dist/app/modules/identity/repositories/robot.mjs +2 -2
  283. package/dist/app/modules/identity/repositories/robot.mjs.map +1 -1
  284. package/dist/app/modules/identity/repositories/user.mjs +2 -2
  285. package/dist/app/modules/identity/repositories/user.mjs.map +1 -1
  286. package/dist/app/modules/oauth2/constants.d.ts +2 -1
  287. package/dist/app/modules/oauth2/constants.d.ts.map +1 -1
  288. package/dist/app/modules/oauth2/constants.mjs +1 -0
  289. package/dist/app/modules/oauth2/constants.mjs.map +1 -1
  290. package/dist/app/modules/oauth2/module.d.ts.map +1 -1
  291. package/dist/app/modules/oauth2/module.mjs +10 -4
  292. package/dist/app/modules/oauth2/module.mjs.map +1 -1
  293. package/dist/app/modules/oauth2/repositories/client/repository.mjs +2 -2
  294. package/dist/app/modules/oauth2/repositories/client/repository.mjs.map +1 -1
  295. package/dist/app/modules/oauth2/repositories/index.d.ts +1 -0
  296. package/dist/app/modules/oauth2/repositories/index.d.ts.map +1 -1
  297. package/dist/app/modules/oauth2/repositories/index.mjs +3 -1
  298. package/dist/app/modules/oauth2/repositories/session-token/index.d.ts +2 -0
  299. package/dist/app/modules/oauth2/repositories/session-token/index.d.ts.map +1 -0
  300. package/dist/app/modules/oauth2/repositories/session-token/index.mjs +5 -0
  301. package/dist/app/modules/oauth2/repositories/session-token/repository.d.ts +17 -0
  302. package/dist/app/modules/oauth2/repositories/session-token/repository.d.ts.map +1 -0
  303. package/dist/app/modules/oauth2/repositories/session-token/repository.mjs +63 -0
  304. package/dist/app/modules/oauth2/repositories/session-token/repository.mjs.map +1 -0
  305. package/dist/app/modules/provisioning/module.d.ts.map +1 -1
  306. package/dist/app/modules/provisioning/module.mjs +0 -1
  307. package/dist/app/modules/provisioning/module.mjs.map +1 -1
  308. package/dist/app/modules/provisioning/sources/default/module.d.ts.map +1 -1
  309. package/dist/app/modules/provisioning/sources/default/module.mjs +15 -56
  310. package/dist/app/modules/provisioning/sources/default/module.mjs.map +1 -1
  311. package/dist/app/modules/provisioning/sources/file/module.d.ts.map +1 -1
  312. package/dist/app/modules/provisioning/sources/file/module.mjs +2 -1
  313. package/dist/app/modules/provisioning/sources/file/module.mjs.map +1 -1
  314. package/dist/cli/commands/migration.d.ts.map +1 -1
  315. package/dist/cli/commands/migration.mjs +12 -4
  316. package/dist/cli/commands/migration.mjs.map +1 -1
  317. package/dist/components/oauth2-cleaner/module.d.ts.map +1 -1
  318. package/dist/components/oauth2-cleaner/module.mjs +3 -0
  319. package/dist/components/oauth2-cleaner/module.mjs.map +1 -1
  320. package/dist/core/authentication/index.mjs +2 -1
  321. package/dist/core/authentication/session/index.mjs +2 -1
  322. package/dist/core/authentication/session/module.d.ts +1 -0
  323. package/dist/core/authentication/session/module.d.ts.map +1 -1
  324. package/dist/core/authentication/session/module.mjs +3 -0
  325. package/dist/core/authentication/session/module.mjs.map +1 -1
  326. package/dist/core/authentication/session/types.d.ts +34 -0
  327. package/dist/core/authentication/session/types.d.ts.map +1 -1
  328. package/dist/core/authentication/session/types.mjs +18 -1
  329. package/dist/core/authentication/session/types.mjs.map +1 -0
  330. package/dist/core/entities/client/service.mjs +25 -7
  331. package/dist/core/entities/client/service.mjs.map +1 -1
  332. package/dist/core/entities/client/web-client.d.ts +5 -3
  333. package/dist/core/entities/client/web-client.d.ts.map +1 -1
  334. package/dist/core/entities/client/web-client.mjs +8 -4
  335. package/dist/core/entities/client/web-client.mjs.map +1 -1
  336. package/dist/core/entities/client-permission/service.d.ts +7 -4
  337. package/dist/core/entities/client-permission/service.d.ts.map +1 -1
  338. package/dist/core/entities/client-permission/service.mjs +59 -19
  339. package/dist/core/entities/client-permission/service.mjs.map +1 -1
  340. package/dist/core/entities/client-role/service.d.ts +3 -2
  341. package/dist/core/entities/client-role/service.d.ts.map +1 -1
  342. package/dist/core/entities/client-role/service.mjs +12 -5
  343. package/dist/core/entities/client-role/service.mjs.map +1 -1
  344. package/dist/core/entities/client-scope/service.d.ts +3 -2
  345. package/dist/core/entities/client-scope/service.d.ts.map +1 -1
  346. package/dist/core/entities/client-scope/service.mjs +12 -5
  347. package/dist/core/entities/client-scope/service.mjs.map +1 -1
  348. package/dist/core/entities/identity-provider-role-mapping/service.d.ts +7 -4
  349. package/dist/core/entities/identity-provider-role-mapping/service.d.ts.map +1 -1
  350. package/dist/core/entities/identity-provider-role-mapping/service.mjs +29 -6
  351. package/dist/core/entities/identity-provider-role-mapping/service.mjs.map +1 -1
  352. package/dist/core/entities/index.d.ts +1 -0
  353. package/dist/core/entities/index.d.ts.map +1 -1
  354. package/dist/core/entities/index.mjs +3 -1
  355. package/dist/core/entities/permission/service.d.ts +3 -5
  356. package/dist/core/entities/permission/service.d.ts.map +1 -1
  357. package/dist/core/entities/permission/service.mjs +30 -24
  358. package/dist/core/entities/permission/service.mjs.map +1 -1
  359. package/dist/core/entities/permission-policy/service.d.ts +3 -2
  360. package/dist/core/entities/permission-policy/service.d.ts.map +1 -1
  361. package/dist/core/entities/permission-policy/service.mjs +12 -5
  362. package/dist/core/entities/permission-policy/service.mjs.map +1 -1
  363. package/dist/core/entities/policy/service.d.ts.map +1 -1
  364. package/dist/core/entities/policy/service.mjs +16 -7
  365. package/dist/core/entities/policy/service.mjs.map +1 -1
  366. package/dist/core/entities/realm/service.mjs +4 -4
  367. package/dist/core/entities/realm/service.mjs.map +1 -1
  368. package/dist/core/entities/realm/types.d.ts +13 -0
  369. package/dist/core/entities/realm/types.d.ts.map +1 -1
  370. package/dist/core/entities/robot/service.d.ts.map +1 -1
  371. package/dist/core/entities/robot/service.mjs +29 -11
  372. package/dist/core/entities/robot/service.mjs.map +1 -1
  373. package/dist/core/entities/robot-permission/service.d.ts +7 -4
  374. package/dist/core/entities/robot-permission/service.d.ts.map +1 -1
  375. package/dist/core/entities/robot-permission/service.mjs +59 -19
  376. package/dist/core/entities/robot-permission/service.mjs.map +1 -1
  377. package/dist/core/entities/robot-role/service.d.ts +3 -2
  378. package/dist/core/entities/robot-role/service.d.ts.map +1 -1
  379. package/dist/core/entities/robot-role/service.mjs +12 -5
  380. package/dist/core/entities/robot-role/service.mjs.map +1 -1
  381. package/dist/core/entities/role/service.d.ts.map +1 -1
  382. package/dist/core/entities/role/service.mjs +16 -7
  383. package/dist/core/entities/role/service.mjs.map +1 -1
  384. package/dist/core/entities/role-attribute/service.d.ts.map +1 -1
  385. package/dist/core/entities/role-attribute/service.mjs +24 -6
  386. package/dist/core/entities/role-attribute/service.mjs.map +1 -1
  387. package/dist/core/entities/role-permission/service.d.ts +7 -4
  388. package/dist/core/entities/role-permission/service.d.ts.map +1 -1
  389. package/dist/core/entities/role-permission/service.mjs +61 -21
  390. package/dist/core/entities/role-permission/service.mjs.map +1 -1
  391. package/dist/core/entities/scope/service.d.ts.map +1 -1
  392. package/dist/core/entities/scope/service.mjs +16 -7
  393. package/dist/core/entities/scope/service.mjs.map +1 -1
  394. package/dist/core/entities/session/index.d.ts +3 -0
  395. package/dist/core/entities/session/index.d.ts.map +1 -0
  396. package/dist/core/entities/session/index.mjs +5 -0
  397. package/dist/core/entities/session/service.d.ts +27 -0
  398. package/dist/core/entities/session/service.d.ts.map +1 -0
  399. package/dist/core/entities/session/service.mjs +151 -0
  400. package/dist/core/entities/session/service.mjs.map +1 -0
  401. package/dist/core/entities/session/types.d.ts +48 -0
  402. package/dist/core/entities/session/types.d.ts.map +1 -0
  403. package/dist/core/entities/session/types.mjs +4 -0
  404. package/dist/core/entities/user/service.d.ts +1 -0
  405. package/dist/core/entities/user/service.d.ts.map +1 -1
  406. package/dist/core/entities/user/service.mjs +29 -11
  407. package/dist/core/entities/user/service.mjs.map +1 -1
  408. package/dist/core/entities/user-attribute/service.d.ts.map +1 -1
  409. package/dist/core/entities/user-attribute/service.mjs +18 -6
  410. package/dist/core/entities/user-attribute/service.mjs.map +1 -1
  411. package/dist/core/entities/user-permission/service.d.ts +7 -4
  412. package/dist/core/entities/user-permission/service.d.ts.map +1 -1
  413. package/dist/core/entities/user-permission/service.mjs +59 -19
  414. package/dist/core/entities/user-permission/service.mjs.map +1 -1
  415. package/dist/core/entities/user-role/service.d.ts +3 -2
  416. package/dist/core/entities/user-role/service.d.ts.map +1 -1
  417. package/dist/core/entities/user-role/service.mjs +12 -5
  418. package/dist/core/entities/user-role/service.mjs.map +1 -1
  419. package/dist/core/identity/index.mjs +2 -1
  420. package/dist/core/identity/password-recovery/service.d.ts.map +1 -1
  421. package/dist/core/identity/password-recovery/service.mjs +2 -1
  422. package/dist/core/identity/password-recovery/service.mjs.map +1 -1
  423. package/dist/core/identity/password-recovery/types.d.ts +1 -0
  424. package/dist/core/identity/password-recovery/types.d.ts.map +1 -1
  425. package/dist/core/identity/permission/checker/service.d.ts.map +1 -1
  426. package/dist/core/identity/permission/checker/service.mjs +12 -9
  427. package/dist/core/identity/permission/checker/service.mjs.map +1 -1
  428. package/dist/core/identity/permission/index.d.ts +1 -0
  429. package/dist/core/identity/permission/index.d.ts.map +1 -1
  430. package/dist/core/identity/permission/index.mjs +2 -1
  431. package/dist/core/identity/permission/junction-grant.d.ts +49 -0
  432. package/dist/core/identity/permission/junction-grant.d.ts.map +1 -0
  433. package/dist/core/identity/permission/junction-grant.mjs +57 -0
  434. package/dist/core/identity/permission/junction-grant.mjs.map +1 -0
  435. package/dist/core/identity/permission/module.d.ts +2 -3
  436. package/dist/core/identity/permission/module.d.ts.map +1 -1
  437. package/dist/core/identity/permission/module.mjs +52 -14
  438. package/dist/core/identity/permission/module.mjs.map +1 -1
  439. package/dist/core/identity/permission/types.d.ts +22 -2
  440. package/dist/core/identity/permission/types.d.ts.map +1 -1
  441. package/dist/core/identity/policy/checker/service.d.ts.map +1 -1
  442. package/dist/core/identity/policy/checker/service.mjs +6 -5
  443. package/dist/core/identity/policy/checker/service.mjs.map +1 -1
  444. package/dist/core/identity/provider/authentication/presets/facebook.d.ts.map +1 -1
  445. package/dist/core/identity/provider/authentication/presets/facebook.mjs +2 -1
  446. package/dist/core/identity/provider/authentication/presets/facebook.mjs.map +1 -1
  447. package/dist/core/identity/provider/authentication/presets/github.d.ts.map +1 -1
  448. package/dist/core/identity/provider/authentication/presets/github.mjs +2 -1
  449. package/dist/core/identity/provider/authentication/presets/github.mjs.map +1 -1
  450. package/dist/core/identity/provider/authentication/presets/google.d.ts.map +1 -1
  451. package/dist/core/identity/provider/authentication/presets/google.mjs +2 -1
  452. package/dist/core/identity/provider/authentication/presets/google.mjs.map +1 -1
  453. package/dist/core/identity/provider/authentication/presets/instagram.d.ts.map +1 -1
  454. package/dist/core/identity/provider/authentication/presets/instagram.mjs +2 -1
  455. package/dist/core/identity/provider/authentication/presets/instagram.mjs.map +1 -1
  456. package/dist/core/identity/provider/authentication/presets/paypal.d.ts.map +1 -1
  457. package/dist/core/identity/provider/authentication/presets/paypal.mjs +2 -1
  458. package/dist/core/identity/provider/authentication/presets/paypal.mjs.map +1 -1
  459. package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts.map +1 -1
  460. package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs +7 -2
  461. package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs.map +1 -1
  462. package/dist/core/identity/provider/authentication/protocols/open-id/module.d.ts +2 -0
  463. package/dist/core/identity/provider/authentication/protocols/open-id/module.d.ts.map +1 -1
  464. package/dist/core/identity/provider/authentication/protocols/open-id/module.mjs +5 -0
  465. package/dist/core/identity/provider/authentication/protocols/open-id/module.mjs.map +1 -1
  466. package/dist/core/identity/registration/service.d.ts.map +1 -1
  467. package/dist/core/identity/registration/service.mjs +9 -6
  468. package/dist/core/identity/registration/service.mjs.map +1 -1
  469. package/dist/core/identity/registration/types.d.ts +1 -0
  470. package/dist/core/identity/registration/types.d.ts.map +1 -1
  471. package/dist/core/identity/resolver/module.d.ts +7 -0
  472. package/dist/core/identity/resolver/module.d.ts.map +1 -1
  473. package/dist/core/identity/resolver/module.mjs +7 -1
  474. package/dist/core/identity/resolver/module.mjs.map +1 -1
  475. package/dist/core/index.mjs +11 -2
  476. package/dist/core/oauth2/authorization/code/index.mjs +1 -0
  477. package/dist/core/oauth2/authorization/code/issuer/module.d.ts +0 -1
  478. package/dist/core/oauth2/authorization/code/issuer/module.d.ts.map +1 -1
  479. package/dist/core/oauth2/authorization/code/issuer/module.mjs +7 -7
  480. package/dist/core/oauth2/authorization/code/issuer/module.mjs.map +1 -1
  481. package/dist/core/oauth2/authorization/code/issuer/types.d.ts +11 -2
  482. package/dist/core/oauth2/authorization/code/issuer/types.d.ts.map +1 -1
  483. package/dist/core/oauth2/authorization/code/verifier/module.d.ts.map +1 -1
  484. package/dist/core/oauth2/authorization/code/verifier/module.mjs +1 -0
  485. package/dist/core/oauth2/authorization/code/verifier/module.mjs.map +1 -1
  486. package/dist/core/oauth2/authorization/code/verifier/types.d.ts +1 -0
  487. package/dist/core/oauth2/authorization/code/verifier/types.d.ts.map +1 -1
  488. package/dist/core/oauth2/authorization/code-request/validator.d.ts.map +1 -1
  489. package/dist/core/oauth2/authorization/code-request/validator.mjs +19 -5
  490. package/dist/core/oauth2/authorization/code-request/validator.mjs.map +1 -1
  491. package/dist/core/oauth2/authorization/code-request/verifier/module.d.ts.map +1 -1
  492. package/dist/core/oauth2/authorization/code-request/verifier/module.mjs +13 -10
  493. package/dist/core/oauth2/authorization/code-request/verifier/module.mjs.map +1 -1
  494. package/dist/core/oauth2/authorization/code-request/verifier/types.d.ts +7 -0
  495. package/dist/core/oauth2/authorization/code-request/verifier/types.d.ts.map +1 -1
  496. package/dist/core/oauth2/authorization/helpers.d.ts +2 -1
  497. package/dist/core/oauth2/authorization/helpers.d.ts.map +1 -1
  498. package/dist/core/oauth2/authorization/helpers.mjs +19 -2
  499. package/dist/core/oauth2/authorization/helpers.mjs.map +1 -1
  500. package/dist/core/oauth2/authorization/module.d.ts +6 -7
  501. package/dist/core/oauth2/authorization/module.d.ts.map +1 -1
  502. package/dist/core/oauth2/authorization/module.mjs +24 -38
  503. package/dist/core/oauth2/authorization/module.mjs.map +1 -1
  504. package/dist/core/oauth2/authorization/types.d.ts +15 -7
  505. package/dist/core/oauth2/authorization/types.d.ts.map +1 -1
  506. package/dist/core/oauth2/client/grant-type.d.ts +9 -0
  507. package/dist/core/oauth2/client/grant-type.d.ts.map +1 -0
  508. package/dist/core/oauth2/client/grant-type.mjs +18 -0
  509. package/dist/core/oauth2/client/grant-type.mjs.map +1 -0
  510. package/dist/core/oauth2/client/index.d.ts +1 -0
  511. package/dist/core/oauth2/client/index.d.ts.map +1 -1
  512. package/dist/core/oauth2/client/index.mjs +2 -1
  513. package/dist/core/oauth2/end-session/index.d.ts +4 -0
  514. package/dist/core/oauth2/end-session/index.d.ts.map +1 -0
  515. package/dist/core/oauth2/end-session/index.mjs +6 -0
  516. package/dist/core/oauth2/end-session/service.d.ts +30 -0
  517. package/dist/core/oauth2/end-session/service.d.ts.map +1 -0
  518. package/dist/core/oauth2/end-session/service.mjs +117 -0
  519. package/dist/core/oauth2/end-session/service.mjs.map +1 -0
  520. package/dist/core/oauth2/end-session/types.d.ts +55 -0
  521. package/dist/core/oauth2/end-session/types.d.ts.map +1 -0
  522. package/dist/core/oauth2/end-session/types.mjs +4 -0
  523. package/dist/core/oauth2/end-session/validator.d.ts +6 -0
  524. package/dist/core/oauth2/end-session/validator.d.ts.map +1 -0
  525. package/dist/core/oauth2/end-session/validator.mjs +23 -0
  526. package/dist/core/oauth2/end-session/validator.mjs.map +1 -0
  527. package/dist/core/oauth2/grant-types/authorize.d.ts +19 -2
  528. package/dist/core/oauth2/grant-types/authorize.d.ts.map +1 -1
  529. package/dist/core/oauth2/grant-types/authorize.mjs +53 -10
  530. package/dist/core/oauth2/grant-types/authorize.mjs.map +1 -1
  531. package/dist/core/oauth2/grant-types/refresh-token.d.ts +21 -2
  532. package/dist/core/oauth2/grant-types/refresh-token.d.ts.map +1 -1
  533. package/dist/core/oauth2/grant-types/refresh-token.mjs +55 -9
  534. package/dist/core/oauth2/grant-types/refresh-token.mjs.map +1 -1
  535. package/dist/core/oauth2/grant-types/types.d.ts +22 -2
  536. package/dist/core/oauth2/grant-types/types.d.ts.map +1 -1
  537. package/dist/core/oauth2/index.d.ts +2 -0
  538. package/dist/core/oauth2/index.d.ts.map +1 -1
  539. package/dist/core/oauth2/index.mjs +7 -3
  540. package/dist/core/oauth2/session-token/index.d.ts +2 -0
  541. package/dist/core/oauth2/session-token/index.d.ts.map +1 -0
  542. package/dist/core/oauth2/session-token/index.mjs +4 -0
  543. package/dist/core/oauth2/session-token/types.d.ts +70 -0
  544. package/dist/core/oauth2/session-token/types.d.ts.map +1 -0
  545. package/dist/core/oauth2/session-token/types.mjs +4 -0
  546. package/dist/core/oauth2/token/issuer/access/module.d.ts +3 -1
  547. package/dist/core/oauth2/token/issuer/access/module.d.ts.map +1 -1
  548. package/dist/core/oauth2/token/issuer/access/module.mjs +12 -1
  549. package/dist/core/oauth2/token/issuer/access/module.mjs.map +1 -1
  550. package/dist/core/oauth2/token/issuer/open-id/module.d.ts.map +1 -1
  551. package/dist/core/oauth2/token/issuer/open-id/module.mjs +1 -1
  552. package/dist/core/oauth2/token/issuer/open-id/module.mjs.map +1 -1
  553. package/dist/core/oauth2/token/issuer/refresh/module.d.ts +3 -1
  554. package/dist/core/oauth2/token/issuer/refresh/module.d.ts.map +1 -1
  555. package/dist/core/oauth2/token/issuer/refresh/module.mjs +12 -1
  556. package/dist/core/oauth2/token/issuer/refresh/module.mjs.map +1 -1
  557. package/dist/core/oauth2/token/revoker/module.d.ts +3 -1
  558. package/dist/core/oauth2/token/revoker/module.d.ts.map +1 -1
  559. package/dist/core/oauth2/token/revoker/module.mjs +4 -1
  560. package/dist/core/oauth2/token/revoker/module.mjs.map +1 -1
  561. package/dist/core/oauth2/token/verifier/module.d.ts.map +1 -1
  562. package/dist/core/oauth2/token/verifier/module.mjs +4 -4
  563. package/dist/core/oauth2/token/verifier/module.mjs.map +1 -1
  564. package/dist/core/oauth2/token/verifier/types.d.ts +6 -0
  565. package/dist/core/oauth2/token/verifier/types.d.ts.map +1 -1
  566. package/dist/core/provisioning/entities/client/relations-validator.d.ts.map +1 -1
  567. package/dist/core/provisioning/entities/client/relations-validator.mjs +3 -2
  568. package/dist/core/provisioning/entities/client/relations-validator.mjs.map +1 -1
  569. package/dist/core/provisioning/entities/index.d.ts +1 -0
  570. package/dist/core/provisioning/entities/index.d.ts.map +1 -1
  571. package/dist/core/provisioning/entities/index.mjs +5 -1
  572. package/dist/core/provisioning/entities/permission/index.d.ts +1 -0
  573. package/dist/core/provisioning/entities/permission/index.d.ts.map +1 -1
  574. package/dist/core/provisioning/entities/permission/index.mjs +2 -1
  575. package/dist/core/provisioning/entities/permission/relations-validator.d.ts +6 -0
  576. package/dist/core/provisioning/entities/permission/relations-validator.d.ts.map +1 -0
  577. package/dist/core/provisioning/entities/permission/relations-validator.mjs +17 -0
  578. package/dist/core/provisioning/entities/permission/relations-validator.mjs.map +1 -0
  579. package/dist/core/provisioning/entities/permission/validator.d.ts.map +1 -1
  580. package/dist/core/provisioning/entities/permission/validator.mjs +3 -0
  581. package/dist/core/provisioning/entities/permission/validator.mjs.map +1 -1
  582. package/dist/core/provisioning/entities/policy/index.d.ts +1 -0
  583. package/dist/core/provisioning/entities/policy/index.d.ts.map +1 -1
  584. package/dist/core/provisioning/entities/policy/index.mjs +2 -1
  585. package/dist/core/provisioning/entities/policy/validator.d.ts +6 -0
  586. package/dist/core/provisioning/entities/policy/validator.d.ts.map +1 -0
  587. package/dist/core/provisioning/entities/policy/validator.mjs +26 -0
  588. package/dist/core/provisioning/entities/policy/validator.mjs.map +1 -0
  589. package/dist/core/provisioning/entities/realm/relations-validator.d.ts.map +1 -1
  590. package/dist/core/provisioning/entities/realm/relations-validator.mjs +9 -52
  591. package/dist/core/provisioning/entities/realm/relations-validator.mjs.map +1 -1
  592. package/dist/core/provisioning/entities/role/relations-validator.d.ts.map +1 -1
  593. package/dist/core/provisioning/entities/role/relations-validator.mjs +4 -0
  594. package/dist/core/provisioning/entities/role/relations-validator.mjs.map +1 -1
  595. package/dist/core/provisioning/entities/role/types.d.ts +8 -5
  596. package/dist/core/provisioning/entities/role/types.d.ts.map +1 -1
  597. package/dist/core/provisioning/entities/root/validator.d.ts.map +1 -1
  598. package/dist/core/provisioning/entities/root/validator.mjs +11 -26
  599. package/dist/core/provisioning/entities/root/validator.mjs.map +1 -1
  600. package/dist/core/provisioning/entities/utils.d.ts +10 -0
  601. package/dist/core/provisioning/entities/utils.d.ts.map +1 -0
  602. package/dist/core/provisioning/entities/utils.mjs +29 -0
  603. package/dist/core/provisioning/entities/utils.mjs.map +1 -0
  604. package/dist/core/provisioning/index.mjs +4 -1
  605. package/dist/core/provisioning/synchronizer/base.d.ts +3 -0
  606. package/dist/core/provisioning/synchronizer/base.d.ts.map +1 -1
  607. package/dist/core/provisioning/synchronizer/base.mjs +3 -0
  608. package/dist/core/provisioning/synchronizer/base.mjs.map +1 -1
  609. package/dist/core/provisioning/synchronizer/client/module.d.ts.map +1 -1
  610. package/dist/core/provisioning/synchronizer/client/module.mjs +1 -0
  611. package/dist/core/provisioning/synchronizer/client/module.mjs.map +1 -1
  612. package/dist/core/provisioning/synchronizer/entity-resolver.d.ts.map +1 -1
  613. package/dist/core/provisioning/synchronizer/entity-resolver.mjs +3 -0
  614. package/dist/core/provisioning/synchronizer/entity-resolver.mjs.map +1 -1
  615. package/dist/core/provisioning/synchronizer/index.mjs +1 -0
  616. package/dist/core/provisioning/synchronizer/permission/module.d.ts.map +1 -1
  617. package/dist/core/provisioning/synchronizer/permission/module.mjs +2 -1
  618. package/dist/core/provisioning/synchronizer/permission/module.mjs.map +1 -1
  619. package/dist/core/provisioning/synchronizer/policy/module.d.ts +2 -0
  620. package/dist/core/provisioning/synchronizer/policy/module.d.ts.map +1 -1
  621. package/dist/core/provisioning/synchronizer/policy/module.mjs +19 -1
  622. package/dist/core/provisioning/synchronizer/policy/module.mjs.map +1 -1
  623. package/dist/core/provisioning/synchronizer/realm/module.d.ts.map +1 -1
  624. package/dist/core/provisioning/synchronizer/realm/module.mjs +1 -0
  625. package/dist/core/provisioning/synchronizer/realm/module.mjs.map +1 -1
  626. package/dist/core/provisioning/synchronizer/robot/module.d.ts.map +1 -1
  627. package/dist/core/provisioning/synchronizer/robot/module.mjs +1 -0
  628. package/dist/core/provisioning/synchronizer/robot/module.mjs.map +1 -1
  629. package/dist/core/provisioning/synchronizer/role/module.d.ts +2 -3
  630. package/dist/core/provisioning/synchronizer/role/module.d.ts.map +1 -1
  631. package/dist/core/provisioning/synchronizer/role/module.mjs +14 -20
  632. package/dist/core/provisioning/synchronizer/role/module.mjs.map +1 -1
  633. package/dist/core/provisioning/synchronizer/role/types.d.ts +1 -2
  634. package/dist/core/provisioning/synchronizer/role/types.d.ts.map +1 -1
  635. package/dist/core/provisioning/synchronizer/scope/module.d.ts.map +1 -1
  636. package/dist/core/provisioning/synchronizer/scope/module.mjs +1 -0
  637. package/dist/core/provisioning/synchronizer/scope/module.mjs.map +1 -1
  638. package/dist/core/provisioning/synchronizer/user/module.d.ts.map +1 -1
  639. package/dist/core/provisioning/synchronizer/user/module.mjs +1 -0
  640. package/dist/core/provisioning/synchronizer/user/module.mjs.map +1 -1
  641. package/dist/core/security/policy/evaluator.d.ts +4 -4
  642. package/dist/core/security/policy/evaluator.d.ts.map +1 -1
  643. package/dist/core/security/policy/evaluator.mjs +19 -18
  644. package/dist/core/security/policy/evaluator.mjs.map +1 -1
  645. package/dist/index.mjs +17 -12
  646. package/dist/swagger.json +585 -23
  647. package/dist/ui/client/.vite/ssr-manifest.json +1981 -577
  648. package/dist/ui/client/assets/index-CP9HCHoS.js +127 -0
  649. package/dist/ui/client/assets/index-VM4JXBXw.css +2 -0
  650. package/dist/ui/client/index.html +2 -2
  651. package/dist/ui/server/assets/{multipart-parser-Dn2Ly9xU.js → multipart-parser-BCMy8Xwv.js} +11 -1
  652. package/dist/ui/server/assets/{multipart-parser-DyM9gi59.js → multipart-parser-BVY8pIV2.js} +11 -1
  653. package/dist/ui/server/server.js +21503 -11128
  654. package/package.json +38 -36
  655. package/dist/ui/client/assets/index-BFXs98mu.js +0 -102
  656. package/dist/ui/client/assets/index-C_-HM1P-.css +0 -2
@@ -0,0 +1,117 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { isSimpleMatch, isUUID } from "@authup/kit";
5
+ import { OAuth2TokenKind } from "@authup/specs";
6
+ //#region src/core/oauth2/end-session/service.ts
7
+ var OAuth2EndSessionService = class {
8
+ tokenVerifier;
9
+ sessionManager;
10
+ clientRepository;
11
+ realmRepository;
12
+ hintGracePeriod;
13
+ constructor(ctx) {
14
+ this.tokenVerifier = ctx.tokenVerifier;
15
+ this.sessionManager = ctx.sessionManager;
16
+ this.clientRepository = ctx.clientRepository;
17
+ this.realmRepository = ctx.realmRepository;
18
+ this.hintGracePeriod = ctx.hintGracePeriod ?? 0;
19
+ }
20
+ async verify(data) {
21
+ let hintVerified = false;
22
+ let sub;
23
+ let subKind;
24
+ let sessionId;
25
+ let hintRealmId;
26
+ let audiences = [];
27
+ if (data.id_token_hint) try {
28
+ const payload = await this.tokenVerifier.verify(data.id_token_hint, {
29
+ ignoreExpiry: true,
30
+ skipActiveCheck: true
31
+ });
32
+ if (payload.kind === OAuth2TokenKind.ID_TOKEN && this.isWithinHintGraceWindow(payload)) {
33
+ hintVerified = true;
34
+ sub = payload.sub;
35
+ subKind = payload.sub_kind;
36
+ sessionId = payload.sid ?? payload.session_id ?? void 0;
37
+ hintRealmId = payload.realm_id ?? void 0;
38
+ const { aud } = payload;
39
+ if (Array.isArray(aud)) audiences = aud.filter((entry) => typeof entry === "string");
40
+ else if (typeof aud === "string") audiences = [aud];
41
+ }
42
+ } catch {}
43
+ const clientId = data.client_id ?? (audiences.length === 1 ? audiences[0] : void 0);
44
+ let client = null;
45
+ if (clientId) {
46
+ const realmKey = data.realm_id ?? data.realm_name ?? (hintVerified ? hintRealmId : void 0);
47
+ const realm = await this.realmRepository.resolve(realmKey, false);
48
+ if (realm) client = await this.clientRepository.findOneByIdOrName(clientId, realm.id);
49
+ else if (!realmKey && isUUID(clientId)) client = await this.clientRepository.findOneByIdOrName(clientId);
50
+ }
51
+ if (hintVerified && data.client_id) {
52
+ const expected = isUUID(data.client_id) ? data.client_id : client?.id;
53
+ if (audiences.length === 0 || !expected || !audiences.includes(expected)) {
54
+ hintVerified = false;
55
+ sub = void 0;
56
+ subKind = void 0;
57
+ sessionId = void 0;
58
+ }
59
+ }
60
+ let clientName;
61
+ let redirectUri;
62
+ if (client) {
63
+ clientName = client.name;
64
+ if (data.post_logout_redirect_uri && this.isValidPostLogoutRedirect(client.post_logout_redirect_uri, data.post_logout_redirect_uri)) redirectUri = data.post_logout_redirect_uri;
65
+ }
66
+ return {
67
+ hintVerified,
68
+ ...hintVerified ? {
69
+ sub,
70
+ subKind,
71
+ sessionId
72
+ } : {},
73
+ ...clientId ? { clientId } : {},
74
+ ...clientName ? { clientName } : {},
75
+ ...redirectUri ? {
76
+ redirectUri,
77
+ ...data.state ? { state: data.state } : {}
78
+ } : {}
79
+ };
80
+ }
81
+ async revoke(sessionId, sub, subKind) {
82
+ const session = await this.sessionManager.findOneById(sessionId);
83
+ if (!session) return false;
84
+ if (session.sub !== sub || session.sub_kind !== subKind) return false;
85
+ await this.sessionManager.revoke(sessionId);
86
+ return true;
87
+ }
88
+ /**
89
+ * With a positive `hintGracePeriod`, an expired hint is honored only within
90
+ * the window past `exp` — beyond it a leaked id_token stops being a
91
+ * replayable remote logout (the hint counts as unverified; the click-gated
92
+ * confirm page still works). 0 keeps spec/Keycloak parity: any expired hint.
93
+ */ isWithinHintGraceWindow(payload) {
94
+ if (this.hintGracePeriod <= 0) return true;
95
+ if (typeof payload.exp !== "number") return false;
96
+ return Math.floor(Date.now() / 1e3) - payload.exp <= this.hintGracePeriod;
97
+ }
98
+ /**
99
+ * A post-logout redirect is honored only when it is an absolute http(s) URL
100
+ * that matches a registered client redirect pattern (defense against open
101
+ * redirects to attacker-controlled URLs).
102
+ */ isValidPostLogoutRedirect(registered, candidate) {
103
+ let parsed;
104
+ try {
105
+ parsed = new URL(candidate);
106
+ } catch {
107
+ return false;
108
+ }
109
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false;
110
+ if (!registered) return false;
111
+ return isSimpleMatch(candidate, registered.split(","));
112
+ }
113
+ };
114
+ //#endregion
115
+ export { OAuth2EndSessionService };
116
+
117
+ //# sourceMappingURL=service.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.mjs","names":["isSimpleMatch","isUUID","OAuth2TokenKind","OAuth2EndSessionService","tokenVerifier","sessionManager","clientRepository","realmRepository","hintGracePeriod","ctx","verify","data","hintVerified","sub","subKind","sessionId","hintRealmId","audiences","id_token_hint","payload","ignoreExpiry","skipActiveCheck","kind","ID_TOKEN","isWithinHintGraceWindow","sub_kind","sid","session_id","undefined","realm_id","aud","Array","isArray","filter","entry","clientId","client_id","length","client","realmKey","realm_name","realm","resolve","findOneByIdOrName","id","expected","includes","clientName","redirectUri","name","post_logout_redirect_uri","isValidPostLogoutRedirect","state","revoke","session","findOneById","exp","nowSeconds","Math","floor","Date","now","registered","candidate","parsed","URL","protocol","split"],"sources":["../../../../src/core/oauth2/end-session/service.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { isSimpleMatch, isUUID } from '@authup/kit';\nimport type { Client } from '@authup/core-kit';\nimport type { OAuth2TokenPayload } from '@authup/specs';\nimport { OAuth2TokenKind } from '@authup/specs';\nimport type { IRealmRepository } from '../../entities/index.ts';\nimport type { ISessionManager } from '../../authentication/index.ts';\nimport type { IOAuth2ClientRepository } from '../client/index.ts';\nimport type { IOAuth2TokenVerifier } from '../token/index.ts';\nimport type {\n IOAuth2EndSessionService,\n OAuth2EndSessionRequest,\n OAuth2EndSessionResult,\n OAuth2EndSessionServiceContext,\n} from './types.ts';\n\nexport class OAuth2EndSessionService implements IOAuth2EndSessionService {\n protected tokenVerifier: IOAuth2TokenVerifier;\n\n protected sessionManager: ISessionManager;\n\n protected clientRepository: IOAuth2ClientRepository;\n\n protected realmRepository: IRealmRepository;\n\n protected hintGracePeriod: number;\n\n constructor(ctx: OAuth2EndSessionServiceContext) {\n this.tokenVerifier = ctx.tokenVerifier;\n this.sessionManager = ctx.sessionManager;\n this.clientRepository = ctx.clientRepository;\n this.realmRepository = ctx.realmRepository;\n this.hintGracePeriod = ctx.hintGracePeriod ?? 0;\n }\n\n async verify(data: OAuth2EndSessionRequest): Promise<OAuth2EndSessionResult> {\n let hintVerified = false;\n let sub: string | undefined;\n let subKind: string | undefined;\n let sessionId: string | undefined;\n let hintRealmId: string | undefined;\n let audiences: string[] = [];\n\n if (data.id_token_hint) {\n try {\n // Signature + kind are the anchors; exp is skipped (a logout hint\n // is routinely expired) and the cache blocklist is irrelevant.\n const payload = await this.tokenVerifier.verify(data.id_token_hint, {\n ignoreExpiry: true,\n skipActiveCheck: true,\n });\n\n // MUST be an id_token — access/refresh tokens also carry\n // session_id, so accepting them would let a leaked access token\n // act as a logout weapon.\n if (payload.kind === OAuth2TokenKind.ID_TOKEN && this.isWithinHintGraceWindow(payload)) {\n hintVerified = true;\n sub = payload.sub;\n subKind = payload.sub_kind;\n sessionId = payload.sid ?? payload.session_id ?? undefined;\n hintRealmId = payload.realm_id ?? undefined;\n // aud may be a single string or an array (JWT spec).\n const { aud } = payload;\n if (Array.isArray(aud)) {\n audiences = aud.filter((entry): entry is string => typeof entry === 'string');\n } else if (typeof aud === 'string') {\n audiences = [aud];\n }\n }\n } catch {\n // forged / unverifiable hint → stays unverified (no revoke)\n }\n }\n\n // Resolve a single client for the aud cross-check and redirect\n // validation: the request's client_id, else the hint's sole audience\n // (ambiguous for a multi-aud hint).\n const clientId = data.client_id ?? (audiences.length === 1 ? audiences[0] : undefined);\n\n let client: Client | null = null;\n if (clientId) {\n // Scope a name-identified client to the request's realm hint; a\n // VERIFIED hint's own realm claim serves as fallback (claims from an\n // unverified hint are never trusted). No master fallback here\n // (unlike /token): a bogus hint must NOT silently resolve a\n // same-named client in master → null realm.\n const realmKey = data.realm_id ?? data.realm_name ?? (hintVerified ? hintRealmId : undefined);\n const realm = await this.realmRepository.resolve(realmKey, false);\n\n // Fail closed instead of dropping the realm predicate: a supplied\n // realm key that does not resolve never degrades to an unscoped\n // lookup, and a NAME-form client_id without any realm key is\n // ambiguous (every realm has a built-in `web` client — same rule as\n // the /authorize verifier). A UUID is globally unique and needs no\n // scope; the sole-aud-derived clientId is always a UUID.\n if (realm) {\n client = await this.clientRepository.findOneByIdOrName(clientId, realm.id);\n } else if (!realmKey && isUUID(clientId)) {\n client = await this.clientRepository.findOneByIdOrName(clientId);\n }\n }\n\n // aud/client_id cross-check: when the request supplies a client_id on a\n // verified hint, it MUST denote one of the hint's audiences. The aud is\n // the client UUID, so a name-form client_id is compared via its resolved\n // client's id. Fail closed: an aud-less hint, or a name that did not\n // resolve, counts as unverified.\n if (hintVerified && data.client_id) {\n const expected = isUUID(data.client_id) ? data.client_id : client?.id;\n if (audiences.length === 0 || !expected || !audiences.includes(expected)) {\n hintVerified = false;\n sub = undefined;\n subKind = undefined;\n sessionId = undefined;\n }\n }\n\n let clientName: string | undefined;\n let redirectUri: string | undefined;\n\n // Redirect validation is independent of hint verification — the\n // click-gated confirm page (unverified hint / hint-less request) still\n // honors a registered post-logout redirect.\n if (client) {\n clientName = client.name;\n if (\n data.post_logout_redirect_uri &&\n this.isValidPostLogoutRedirect(client.post_logout_redirect_uri, data.post_logout_redirect_uri)\n ) {\n redirectUri = data.post_logout_redirect_uri;\n }\n }\n\n return {\n hintVerified,\n ...(hintVerified ? {\n sub,\n subKind,\n sessionId,\n } : {}),\n ...(clientId ? { clientId } : {}),\n ...(clientName ? { clientName } : {}),\n ...(redirectUri ? { redirectUri, ...(data.state ? { state: data.state } : {}) } : {}),\n };\n }\n\n async revoke(sessionId: string, sub: string, subKind: string): Promise<boolean> {\n const session = await this.sessionManager.findOneById(sessionId);\n if (!session) {\n return false;\n }\n\n // Never revoke a session that does not belong to the hint's subject.\n if (session.sub !== sub || session.sub_kind !== subKind) {\n return false;\n }\n\n await this.sessionManager.revoke(sessionId);\n return true;\n }\n\n /**\n * With a positive `hintGracePeriod`, an expired hint is honored only within\n * the window past `exp` — beyond it a leaked id_token stops being a\n * replayable remote logout (the hint counts as unverified; the click-gated\n * confirm page still works). 0 keeps spec/Keycloak parity: any expired hint.\n */\n protected isWithinHintGraceWindow(payload: OAuth2TokenPayload): boolean {\n if (this.hintGracePeriod <= 0) {\n return true;\n }\n\n // a bounded window without an exp claim to judge against fails closed\n if (typeof payload.exp !== 'number') {\n return false;\n }\n\n const nowSeconds = Math.floor(Date.now() / 1000);\n return nowSeconds - payload.exp <= this.hintGracePeriod;\n }\n\n /**\n * A post-logout redirect is honored only when it is an absolute http(s) URL\n * that matches a registered client redirect pattern (defense against open\n * redirects to attacker-controlled URLs).\n */\n protected isValidPostLogoutRedirect(\n registered: string | null | undefined,\n candidate: string,\n ): boolean {\n let parsed: URL;\n try {\n parsed = new URL(candidate);\n } catch {\n return false;\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return false;\n }\n\n if (!registered) {\n return false;\n }\n\n return isSimpleMatch(candidate, registered.split(','));\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { IRealmRepository } from '../../entities/index.ts';
2
+ import type { ISessionManager } from '../../authentication/index.ts';
3
+ import type { IOAuth2ClientRepository } from '../client/index.ts';
4
+ import type { IOAuth2TokenVerifier } from '../token/index.ts';
5
+ export type OAuth2EndSessionRequest = {
6
+ id_token_hint?: string;
7
+ client_id?: string;
8
+ post_logout_redirect_uri?: string;
9
+ state?: string;
10
+ realm_id?: string;
11
+ realm_name?: string;
12
+ };
13
+ export type OAuth2EndSessionResult = {
14
+ /**
15
+ * True when a signature-verified id_token_hint proved possession. Only then
16
+ * are `sub` / `sessionId` populated and a server-side revoke authorized.
17
+ */
18
+ hintVerified: boolean;
19
+ sub?: string;
20
+ subKind?: string;
21
+ sessionId?: string;
22
+ clientId?: string;
23
+ clientName?: string;
24
+ /**
25
+ * The post-logout redirect — present ONLY when it matched a registered
26
+ * client pattern (open-redirect guard). `state` rides only alongside it.
27
+ */
28
+ redirectUri?: string;
29
+ state?: string;
30
+ };
31
+ export type OAuth2EndSessionServiceContext = {
32
+ tokenVerifier: IOAuth2TokenVerifier;
33
+ sessionManager: ISessionManager;
34
+ clientRepository: IOAuth2ClientRepository;
35
+ realmRepository: IRealmRepository;
36
+ /**
37
+ * Seconds past its `exp` an (expired) id_token_hint is still accepted for
38
+ * a server-side revoke (config `endSessionHintGracePeriod`).
39
+ * 0 (default) = unbounded — spec/Keycloak parity.
40
+ */
41
+ hintGracePeriod?: number;
42
+ };
43
+ export interface IOAuth2EndSessionService {
44
+ /**
45
+ * Verify the request (id_token_hint signature + kind + aud, redirect
46
+ * validation). Pure — performs no mutation.
47
+ */
48
+ verify(data: OAuth2EndSessionRequest): Promise<OAuth2EndSessionResult>;
49
+ /**
50
+ * Revoke the session ONLY when it belongs to the hint's subject.
51
+ * @returns whether a session was revoked.
52
+ */
53
+ revoke(sessionId: string, sub: string, subKind: string): Promise<boolean>;
54
+ }
55
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/end-session/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,MAAM,MAAM,uBAAuB,GAAG;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACjC;;;OAGG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IACzC,aAAa,EAAE,oBAAoB,CAAC;IACpC,cAAc,EAAE,eAAe,CAAC;IAChC,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,eAAe,EAAE,gBAAgB,CAAC;IAClC;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACrC;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAEvE;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7E"}
@@ -0,0 +1,4 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ export {};
@@ -0,0 +1,6 @@
1
+ import { Container } from 'validup';
2
+ import type { OAuth2EndSessionRequest } from './types.ts';
3
+ export declare class OAuth2EndSessionRequestValidator extends Container<OAuth2EndSessionRequest> {
4
+ protected initialize(): void;
5
+ }
6
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/end-session/validator.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAS1D,qBAAa,gCAAiC,SAAQ,SAAS,CAAC,uBAAuB,CAAC;IACpF,SAAS,CAAC,UAAU;CA0CvB"}
@@ -0,0 +1,23 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { Container } from "validup";
5
+ import { createValidator } from "@validup/zod";
6
+ import { z } from "zod";
7
+ //#region src/core/oauth2/end-session/validator.ts
8
+ const blankAsAbsent = (schema) => z.preprocess((value) => typeof value === "string" && value.trim() === "" ? void 0 : value, schema);
9
+ var OAuth2EndSessionRequestValidator = class extends Container {
10
+ initialize() {
11
+ super.initialize();
12
+ this.mount("id_token_hint", { optional: true }, createValidator(blankAsAbsent(z.string().max(4096).nullable().optional())));
13
+ this.mount("client_id", { optional: true }, createValidator(blankAsAbsent(z.string().max(256).nullable().optional())));
14
+ this.mount("post_logout_redirect_uri", { optional: true }, createValidator(blankAsAbsent(z.string().url().max(2e3).nullable().optional())));
15
+ this.mount("state", { optional: true }, createValidator(blankAsAbsent(z.string().max(2048).nullable().optional())));
16
+ this.mount("realm_id", { optional: true }, createValidator(blankAsAbsent(z.string().trim().toLowerCase().max(256).nullable().optional())));
17
+ this.mount("realm_name", { optional: true }, createValidator(blankAsAbsent(z.string().trim().toLowerCase().max(256).nullable().optional())));
18
+ }
19
+ };
20
+ //#endregion
21
+ export { OAuth2EndSessionRequestValidator };
22
+
23
+ //# sourceMappingURL=validator.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.mjs","names":["createValidator","Container","z","blankAsAbsent","schema","preprocess","value","trim","undefined","OAuth2EndSessionRequestValidator","initialize","mount","optional","string","max","nullable","url","toLowerCase"],"sources":["../../../../src/core/oauth2/end-session/validator.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { createValidator } from '@validup/zod';\nimport { Container } from 'validup';\nimport { z } from 'zod';\nimport type { OAuth2EndSessionRequest } from './types.ts';\n\n// A blank param (e.g. a stray `?state=` from an RP template) is absent,\n// not a validation failure — it must not discard the rest of the request.\nconst blankAsAbsent = (schema: z.ZodType) => z.preprocess(\n (value) => (typeof value === 'string' && value.trim() === '' ? undefined : value),\n schema,\n);\n\nexport class OAuth2EndSessionRequestValidator extends Container<OAuth2EndSessionRequest> {\n protected initialize() {\n super.initialize();\n\n this.mount(\n 'id_token_hint',\n { optional: true },\n createValidator(blankAsAbsent(z.string().max(4096).nullable().optional())),\n );\n\n this.mount(\n 'client_id',\n { optional: true },\n createValidator(blankAsAbsent(z.string().max(256).nullable().optional())),\n );\n\n this.mount(\n 'post_logout_redirect_uri',\n { optional: true },\n createValidator(blankAsAbsent(z.string().url().max(2000).nullable().optional())),\n );\n\n this.mount(\n 'state',\n { optional: true },\n createValidator(blankAsAbsent(z.string().max(2048).nullable().optional())),\n );\n\n // Canonical identifier form (layer 3): no other validator runs on the\n // end-session request, so the realm hint is canonicalized at this\n // ingress — same contract as the token endpoint's readRealmHint.\n this.mount(\n 'realm_id',\n { optional: true },\n createValidator(blankAsAbsent(z.string().trim().toLowerCase().max(256).nullable().optional())),\n );\n\n this.mount(\n 'realm_name',\n { optional: true },\n createValidator(blankAsAbsent(z.string().trim().toLowerCase().max(256).nullable().optional())),\n );\n }\n}\n"],"mappings":";;;;;;;AAcA,MAAMG,iBAAiBC,WAAsBF,EAAEG,YAC1CC,UAAW,OAAOA,UAAU,YAAYA,MAAMC,KAAI,MAAO,KAAKC,KAAAA,IAAYF,OAC3EF,MAAAA;AAGJ,IAAaK,mCAAb,cAAsDR,UAAAA;CACxCS,aAAa;EACnB,MAAMA,WAAAA;EAEN,KAAKC,MACD,iBACA,EAAEC,UAAU,KAAK,GACjBZ,gBAAgBG,cAAcD,EAAEW,OAAM,CAAA,CAAGC,IAAI,IAAA,CAAA,CAAMC,SAAQ,CAAA,CAAGH,SAAQ,CAAA,CAAA,CAAA;EAG1E,KAAKD,MACD,aACA,EAAEC,UAAU,KAAK,GACjBZ,gBAAgBG,cAAcD,EAAEW,OAAM,CAAA,CAAGC,IAAI,GAAA,CAAA,CAAKC,SAAQ,CAAA,CAAGH,SAAQ,CAAA,CAAA,CAAA;EAGzE,KAAKD,MACD,4BACA,EAAEC,UAAU,KAAK,GACjBZ,gBAAgBG,cAAcD,EAAEW,OAAM,CAAA,CAAGG,IAAG,CAAA,CAAGF,IAAI,GAAA,CAAA,CAAMC,SAAQ,CAAA,CAAGH,SAAQ,CAAA,CAAA,CAAA;EAGhF,KAAKD,MACD,SACA,EAAEC,UAAU,KAAK,GACjBZ,gBAAgBG,cAAcD,EAAEW,OAAM,CAAA,CAAGC,IAAI,IAAA,CAAA,CAAMC,SAAQ,CAAA,CAAGH,SAAQ,CAAA,CAAA,CAAA;EAM1E,KAAKD,MACD,YACA,EAAEC,UAAU,KAAK,GACjBZ,gBAAgBG,cAAcD,EAAEW,OAAM,CAAA,CAAGN,KAAI,CAAA,CAAGU,YAAW,CAAA,CAAGH,IAAI,GAAA,CAAA,CAAKC,SAAQ,CAAA,CAAGH,SAAQ,CAAA,CAAA,CAAA;EAG9F,KAAKD,MACD,cACA,EAAEC,UAAU,KAAK,GACjBZ,gBAAgBG,cAAcD,EAAEW,OAAM,CAAA,CAAGN,KAAI,CAAA,CAAGU,YAAW,CAAA,CAAGH,IAAI,GAAA,CAAA,CAAKC,SAAQ,CAAA,CAAGH,SAAQ,CAAA,CAAA,CAAA;CAElG;AACJ"}
@@ -1,11 +1,28 @@
1
1
  import type { OAuth2TokenGrantResponse } from '@authup/specs';
2
- import type { OAuth2AuthorizationCode } from '@authup/core-kit';
3
- import type { IOAuth2TokenIssuer } from '../token/index.ts';
2
+ import type { OAuth2AuthorizationCode, Session } from '@authup/core-kit';
3
+ import type { IOAuth2KeyRepository } from '../key/index.ts';
4
+ import type { IOAuth2OpenIDTokenIssuer, IOAuth2TokenIssuer } from '../token/index.ts';
4
5
  import { OAuth2BaseGrant } from './base.ts';
5
6
  import type { IOAuth2Grant, OAuth2AuthorizeGrantContext, OAuth2GrantRunWIthOptions } from './types.ts';
6
7
  export declare class OAuth2AuthorizeGrant extends OAuth2BaseGrant<OAuth2AuthorizationCode> implements IOAuth2Grant {
7
8
  protected refreshTokenIssuer: IOAuth2TokenIssuer;
9
+ protected openIdTokenIssuer: IOAuth2OpenIDTokenIssuer;
10
+ protected keyRepository: IOAuth2KeyRepository;
8
11
  constructor(ctx: OAuth2AuthorizeGrantContext);
9
12
  runWith(authorizationCode: OAuth2AuthorizationCode, options?: OAuth2GrantRunWIthOptions): Promise<OAuth2TokenGrantResponse>;
13
+ /**
14
+ * Reuse the bearer's session when the authorization code was issued from an
15
+ * (interactive) `/authorize` request that carried one — otherwise the
16
+ * interactive login would create a second session (the abandoned bearer
17
+ * session that authenticated `POST /authorize`, plus this one).
18
+ *
19
+ * The reuse is gated on the session still existing and belonging to the
20
+ * same subject/realm as the code (defense in depth — the id is
21
+ * server-derived from the authenticated bearer, never client input). Any
22
+ * mismatch, or a session-less authorize flow (external IdP, non-interactive
23
+ * clients), falls back to creating a fresh session — preserving prior
24
+ * behavior.
25
+ */
26
+ protected resolveSession(authorizationCode: OAuth2AuthorizationCode, options: OAuth2GrantRunWIthOptions): Promise<Session>;
10
27
  }
11
28
  //# sourceMappingURL=authorize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/grant-types/authorize.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,wBAAwB,EAAsB,MAAM,eAAe,CAAC;AAElF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAEhE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,2BAA2B,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAIvG,qBAAa,oBAAqB,SAAQ,eAAe,CAAC,uBAAuB,CAAE,YAAW,YAAY;IACtG,SAAS,CAAC,kBAAkB,EAAG,kBAAkB,CAAC;gBAEtC,GAAG,EAAE,2BAA2B;IAStC,OAAO,CACT,iBAAiB,EAAE,uBAAuB,EAC1C,OAAO,GAAE,yBAA8B,GACvC,OAAO,CAAC,wBAAwB,CAAC;CAyCxC"}
1
+ {"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/grant-types/authorize.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,wBAAwB,EAAsB,MAAM,eAAe,CAAC;AAElF,OAAO,KAAK,EAAE,uBAAuB,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAGzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,2BAA2B,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAIvG,qBAAa,oBAAqB,SAAQ,eAAe,CAAC,uBAAuB,CAAE,YAAW,YAAY;IACtG,SAAS,CAAC,kBAAkB,EAAG,kBAAkB,CAAC;IAElD,SAAS,CAAC,iBAAiB,EAAG,wBAAwB,CAAC;IAEvD,SAAS,CAAC,aAAa,EAAG,oBAAoB,CAAC;gBAEnC,GAAG,EAAE,2BAA2B;IAWtC,OAAO,CACT,iBAAiB,EAAE,uBAAuB,EAC1C,OAAO,GAAE,yBAA8B,GACvC,OAAO,CAAC,wBAAwB,CAAC;IA6DrC;;;;;;;;;;;;OAYG;cACa,cAAc,CAC1B,iBAAiB,EAAE,uBAAuB,EAC1C,OAAO,EAAE,yBAAyB,GAClC,OAAO,CAAC,OAAO,CAAC;CAwBvB"}
@@ -1,29 +1,27 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
+ import { buildOAuth2TokenHash } from "../authorization/helpers.mjs";
4
5
  import { OAuth2BaseGrant } from "./base.mjs";
5
6
  import { buildOAuth2BearerTokenResponse } from "../response/bearer.mjs";
6
7
  import { ScopeName } from "@authup/core-kit";
7
- import { hasOAuth2Scopes } from "@authup/specs";
8
+ import { JWKError, hasOAuth2Scopes } from "@authup/specs";
8
9
  //#region src/core/oauth2/grant-types/authorize.ts
9
10
  var OAuth2AuthorizeGrant = class extends OAuth2BaseGrant {
10
11
  refreshTokenIssuer;
12
+ openIdTokenIssuer;
13
+ keyRepository;
11
14
  constructor(ctx) {
12
15
  super({
13
16
  accessTokenIssuer: ctx.accessTokenIssuer,
14
17
  sessionManager: ctx.sessionManager
15
18
  });
16
19
  this.refreshTokenIssuer = ctx.refreshTokenIssuer;
20
+ this.openIdTokenIssuer = ctx.openIdTokenIssuer;
21
+ this.keyRepository = ctx.keyRepository;
17
22
  }
18
23
  async runWith(authorizationCode, options = {}) {
19
- const session = await this.sessionManager.create({
20
- user_agent: options.userAgent,
21
- ip_address: options.ipAddress,
22
- realm_id: authorizationCode.realm_id,
23
- client_id: authorizationCode.client_id,
24
- sub_kind: authorizationCode.sub_kind,
25
- sub: authorizationCode.sub
26
- });
24
+ const session = await this.resolveSession(authorizationCode, options);
27
25
  const issuePayload = {
28
26
  user_agent: options.userAgent,
29
27
  remote_address: options.ipAddress,
@@ -43,9 +41,54 @@ var OAuth2AuthorizeGrant = class extends OAuth2BaseGrant {
43
41
  refreshToken,
44
42
  refreshTokenPayload
45
43
  };
46
- if (authorizationCode.scope && hasOAuth2Scopes(authorizationCode.scope, ScopeName.OPEN_ID)) buildContext.idToken = authorizationCode.id_token || void 0;
44
+ if (authorizationCode.scope && hasOAuth2Scopes(authorizationCode.scope, ScopeName.OPEN_ID)) {
45
+ const key = await this.keyRepository.findByRealmId(authorizationCode.realm_id);
46
+ if (!key) throw JWKError.notFoundForRealm(authorizationCode.realm_id, authorizationCode.realm_name);
47
+ const [idToken] = await this.openIdTokenIssuer.issue({
48
+ sub: authorizationCode.sub || void 0,
49
+ sub_kind: authorizationCode.sub_kind,
50
+ realm_id: authorizationCode.realm_id,
51
+ realm_name: authorizationCode.realm_name,
52
+ scope: authorizationCode.scope || void 0,
53
+ client_id: authorizationCode.client_id || void 0,
54
+ ...authorizationCode.nonce ? { nonce: authorizationCode.nonce } : {},
55
+ ...typeof authorizationCode.auth_time === "number" ? { auth_time: authorizationCode.auth_time } : {},
56
+ sid: session.id,
57
+ at_hash: await buildOAuth2TokenHash(accessToken, key.signature_algorithm)
58
+ });
59
+ buildContext.idToken = idToken;
60
+ }
47
61
  return buildOAuth2BearerTokenResponse(buildContext);
48
62
  }
63
+ /**
64
+ * Reuse the bearer's session when the authorization code was issued from an
65
+ * (interactive) `/authorize` request that carried one — otherwise the
66
+ * interactive login would create a second session (the abandoned bearer
67
+ * session that authenticated `POST /authorize`, plus this one).
68
+ *
69
+ * The reuse is gated on the session still existing and belonging to the
70
+ * same subject/realm as the code (defense in depth — the id is
71
+ * server-derived from the authenticated bearer, never client input). Any
72
+ * mismatch, or a session-less authorize flow (external IdP, non-interactive
73
+ * clients), falls back to creating a fresh session — preserving prior
74
+ * behavior.
75
+ */ async resolveSession(authorizationCode, options) {
76
+ if (authorizationCode.session_id) {
77
+ const existing = await this.sessionManager.findOneById(authorizationCode.session_id);
78
+ if (existing && existing.sub === authorizationCode.sub && existing.sub_kind === authorizationCode.sub_kind && existing.realm_id === authorizationCode.realm_id) {
79
+ existing.client_id = authorizationCode.client_id || null;
80
+ return this.sessionManager.refresh(existing);
81
+ }
82
+ }
83
+ return this.sessionManager.create({
84
+ user_agent: options.userAgent,
85
+ ip_address: options.ipAddress,
86
+ realm_id: authorizationCode.realm_id,
87
+ client_id: authorizationCode.client_id,
88
+ sub_kind: authorizationCode.sub_kind,
89
+ sub: authorizationCode.sub
90
+ });
91
+ }
49
92
  };
50
93
  //#endregion
51
94
  export { OAuth2AuthorizeGrant };
@@ -1 +1 @@
1
- {"version":3,"file":"authorize.mjs","names":["hasOAuth2Scopes","ScopeName","OAuth2BaseGrant","buildOAuth2BearerTokenResponse","OAuth2AuthorizeGrant","refreshTokenIssuer","ctx","accessTokenIssuer","sessionManager","runWith","authorizationCode","options","session","create","user_agent","userAgent","ip_address","ipAddress","realm_id","client_id","sub_kind","sub","issuePayload","remote_address","session_id","id","undefined","realm_name","scope","accessToken","accessTokenPayload","issue","refreshToken","refreshTokenPayload","buildContext","OPEN_ID","idToken","id_token"],"sources":["../../../../src/core/oauth2/grant-types/authorize.ts"],"sourcesContent":["/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2TokenGrantResponse, OAuth2TokenPayload } from '@authup/specs';\nimport { hasOAuth2Scopes } from '@authup/specs';\nimport type { OAuth2AuthorizationCode } from '@authup/core-kit';\nimport { ScopeName } from '@authup/core-kit';\nimport type { IOAuth2TokenIssuer } from '../token/index.ts';\nimport { OAuth2BaseGrant } from './base.ts';\nimport type { IOAuth2Grant, OAuth2AuthorizeGrantContext, OAuth2GrantRunWIthOptions } from './types.ts';\nimport type { OAuth2BearerResponseBuildContext } from '../response/index.ts';\nimport { buildOAuth2BearerTokenResponse } from '../response/index.ts';\n\nexport class OAuth2AuthorizeGrant extends OAuth2BaseGrant<OAuth2AuthorizationCode> implements IOAuth2Grant {\n protected refreshTokenIssuer : IOAuth2TokenIssuer;\n\n constructor(ctx: OAuth2AuthorizeGrantContext) {\n super({\n accessTokenIssuer: ctx.accessTokenIssuer,\n sessionManager: ctx.sessionManager,\n });\n\n this.refreshTokenIssuer = ctx.refreshTokenIssuer;\n }\n\n async runWith(\n authorizationCode: OAuth2AuthorizationCode,\n options: OAuth2GrantRunWIthOptions = {},\n ) : Promise<OAuth2TokenGrantResponse> {\n const session = await this.sessionManager.create({\n user_agent: options.userAgent,\n ip_address: options.ipAddress,\n realm_id: authorizationCode.realm_id,\n client_id: authorizationCode.client_id,\n sub_kind: authorizationCode.sub_kind,\n sub: authorizationCode.sub,\n });\n\n const issuePayload : Partial<OAuth2TokenPayload> = {\n user_agent: options.userAgent,\n remote_address: options.ipAddress,\n session_id: session.id,\n sub: authorizationCode.sub || undefined,\n sub_kind: authorizationCode.sub_kind,\n realm_id: authorizationCode.realm_id,\n realm_name: authorizationCode.realm_name,\n scope: authorizationCode.scope || undefined,\n client_id: authorizationCode.client_id || undefined,\n };\n\n const [accessToken, accessTokenPayload] = await this.accessTokenIssuer.issue(issuePayload);\n const [refreshToken, refreshTokenPayload] = await this.refreshTokenIssuer.issue(issuePayload);\n\n const buildContext : OAuth2BearerResponseBuildContext = {\n accessToken,\n accessTokenPayload,\n refreshToken,\n refreshTokenPayload,\n };\n\n if (\n authorizationCode.scope &&\n hasOAuth2Scopes(authorizationCode.scope, ScopeName.OPEN_ID)\n ) {\n buildContext.idToken = authorizationCode.id_token || undefined;\n }\n\n return buildOAuth2BearerTokenResponse(buildContext);\n }\n}\n"],"mappings":";;;;;;;;AAiBA,IAAaI,uBAAb,cAA0CF,gBAAAA;CAC5BG;CAEV,YAAYC,KAAkC;EAC1C,MAAM;GACFC,mBAAmBD,IAAIC;GACvBC,gBAAgBF,IAAIE;EACxB,CAAA;EAEA,KAAKH,qBAAqBC,IAAID;CAClC;CAEA,MAAMI,QACFC,mBACAC,UAAqC,CAAC,GACJ;EAClC,MAAMC,UAAU,MAAM,KAAKJ,eAAeK,OAAO;GAC7CC,YAAYH,QAAQI;GACpBC,YAAYL,QAAQM;GACpBC,UAAUR,kBAAkBQ;GAC5BC,WAAWT,kBAAkBS;GAC7BC,UAAUV,kBAAkBU;GAC5BC,KAAKX,kBAAkBW;EAC3B,CAAA;EAEA,MAAMC,eAA6C;GAC/CR,YAAYH,QAAQI;GACpBQ,gBAAgBZ,QAAQM;GACxBO,YAAYZ,QAAQa;GACpBJ,KAAKX,kBAAkBW,OAAOK,KAAAA;GAC9BN,UAAUV,kBAAkBU;GAC5BF,UAAUR,kBAAkBQ;GAC5BS,YAAYjB,kBAAkBiB;GAC9BC,OAAOlB,kBAAkBkB,SAASF,KAAAA;GAClCP,WAAWT,kBAAkBS,aAAaO,KAAAA;EAC9C;EAEA,MAAM,CAACG,aAAaC,sBAAsB,MAAM,KAAKvB,kBAAkBwB,MAAMT,YAAAA;EAC7E,MAAM,CAACU,cAAcC,uBAAuB,MAAM,KAAK5B,mBAAmB0B,MAAMT,YAAAA;EAEhF,MAAMY,eAAkD;GACpDL;GACAC;GACAE;GACAC;EACJ;EAEA,IACIvB,kBAAkBkB,SAClB5B,gBAAgBU,kBAAkBkB,OAAO3B,UAAUkC,OAAO,GAE1DD,aAAaE,UAAU1B,kBAAkB2B,YAAYX,KAAAA;EAGzD,OAAOvB,+BAA+B+B,YAAAA;CAC1C;AACJ"}
1
+ {"version":3,"file":"authorize.mjs","names":["JWKError","hasOAuth2Scopes","ScopeName","buildOAuth2TokenHash","OAuth2BaseGrant","buildOAuth2BearerTokenResponse","OAuth2AuthorizeGrant","refreshTokenIssuer","openIdTokenIssuer","keyRepository","ctx","accessTokenIssuer","sessionManager","runWith","authorizationCode","options","session","resolveSession","issuePayload","user_agent","userAgent","remote_address","ipAddress","session_id","id","sub","undefined","sub_kind","realm_id","realm_name","scope","client_id","accessToken","accessTokenPayload","issue","refreshToken","refreshTokenPayload","buildContext","OPEN_ID","key","findByRealmId","notFoundForRealm","idToken","nonce","auth_time","sid","at_hash","signature_algorithm","existing","findOneById","refresh","create","ip_address"],"sources":["../../../../src/core/oauth2/grant-types/authorize.ts"],"sourcesContent":["/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2TokenGrantResponse, OAuth2TokenPayload } from '@authup/specs';\nimport { JWKError, hasOAuth2Scopes } from '@authup/specs';\nimport type { OAuth2AuthorizationCode, Session } from '@authup/core-kit';\nimport { ScopeName } from '@authup/core-kit';\nimport { buildOAuth2TokenHash } from '../authorization/helpers.ts';\nimport type { IOAuth2KeyRepository } from '../key/index.ts';\nimport type { IOAuth2OpenIDTokenIssuer, IOAuth2TokenIssuer } from '../token/index.ts';\nimport { OAuth2BaseGrant } from './base.ts';\nimport type { IOAuth2Grant, OAuth2AuthorizeGrantContext, OAuth2GrantRunWIthOptions } from './types.ts';\nimport type { OAuth2BearerResponseBuildContext } from '../response/index.ts';\nimport { buildOAuth2BearerTokenResponse } from '../response/index.ts';\n\nexport class OAuth2AuthorizeGrant extends OAuth2BaseGrant<OAuth2AuthorizationCode> implements IOAuth2Grant {\n protected refreshTokenIssuer : IOAuth2TokenIssuer;\n\n protected openIdTokenIssuer : IOAuth2OpenIDTokenIssuer;\n\n protected keyRepository : IOAuth2KeyRepository;\n\n constructor(ctx: OAuth2AuthorizeGrantContext) {\n super({\n accessTokenIssuer: ctx.accessTokenIssuer,\n sessionManager: ctx.sessionManager,\n });\n\n this.refreshTokenIssuer = ctx.refreshTokenIssuer;\n this.openIdTokenIssuer = ctx.openIdTokenIssuer;\n this.keyRepository = ctx.keyRepository;\n }\n\n async runWith(\n authorizationCode: OAuth2AuthorizationCode,\n options: OAuth2GrantRunWIthOptions = {},\n ) : Promise<OAuth2TokenGrantResponse> {\n const session = await this.resolveSession(authorizationCode, options);\n\n const issuePayload : Partial<OAuth2TokenPayload> = {\n user_agent: options.userAgent,\n remote_address: options.ipAddress,\n session_id: session.id,\n sub: authorizationCode.sub || undefined,\n sub_kind: authorizationCode.sub_kind,\n realm_id: authorizationCode.realm_id,\n realm_name: authorizationCode.realm_name,\n scope: authorizationCode.scope || undefined,\n client_id: authorizationCode.client_id || undefined,\n };\n\n const [accessToken, accessTokenPayload] = await this.accessTokenIssuer.issue(issuePayload);\n const [refreshToken, refreshTokenPayload] = await this.refreshTokenIssuer.issue(issuePayload);\n\n const buildContext : OAuth2BearerResponseBuildContext = {\n accessToken,\n accessTokenPayload,\n refreshToken,\n refreshTokenPayload,\n };\n\n // The id_token is minted HERE — after resolveSession — so its `sid`\n // references the real backing session for the reuse branch, the\n // fallback branch, and session-less (federated IdP) codes alike.\n // `auth_time` is the authentication instant captured on the code.\n if (\n authorizationCode.scope &&\n hasOAuth2Scopes(authorizationCode.scope, ScopeName.OPEN_ID)\n ) {\n // The at_hash digest follows the id_token's JWS alg (OIDC Core\n // §3.1.3.6) — the alg of the realm key the openid issuer signs\n // with. The access token above was signed with the same key, so a\n // missing key would already have thrown; this guard fails closed.\n const key = await this.keyRepository.findByRealmId(authorizationCode.realm_id);\n if (!key) {\n throw JWKError.notFoundForRealm(authorizationCode.realm_id, authorizationCode.realm_name);\n }\n\n const [idToken] = await this.openIdTokenIssuer.issue({\n sub: authorizationCode.sub || undefined,\n sub_kind: authorizationCode.sub_kind,\n realm_id: authorizationCode.realm_id,\n realm_name: authorizationCode.realm_name,\n scope: authorizationCode.scope || undefined,\n client_id: authorizationCode.client_id || undefined,\n ...(authorizationCode.nonce ? { nonce: authorizationCode.nonce } : {}),\n ...(typeof authorizationCode.auth_time === 'number' ? { auth_time: authorizationCode.auth_time } : {}),\n sid: session.id,\n at_hash: await buildOAuth2TokenHash(accessToken, key.signature_algorithm),\n });\n\n buildContext.idToken = idToken;\n }\n\n return buildOAuth2BearerTokenResponse(buildContext);\n }\n\n /**\n * Reuse the bearer's session when the authorization code was issued from an\n * (interactive) `/authorize` request that carried one — otherwise the\n * interactive login would create a second session (the abandoned bearer\n * session that authenticated `POST /authorize`, plus this one).\n *\n * The reuse is gated on the session still existing and belonging to the\n * same subject/realm as the code (defense in depth — the id is\n * server-derived from the authenticated bearer, never client input). Any\n * mismatch, or a session-less authorize flow (external IdP, non-interactive\n * clients), falls back to creating a fresh session — preserving prior\n * behavior.\n */\n protected async resolveSession(\n authorizationCode: OAuth2AuthorizationCode,\n options: OAuth2GrantRunWIthOptions,\n ) : Promise<Session> {\n if (authorizationCode.session_id) {\n const existing = await this.sessionManager.findOneById(authorizationCode.session_id);\n if (\n existing &&\n existing.sub === authorizationCode.sub &&\n existing.sub_kind === authorizationCode.sub_kind &&\n existing.realm_id === authorizationCode.realm_id\n ) {\n existing.client_id = authorizationCode.client_id || null;\n\n return this.sessionManager.refresh(existing);\n }\n }\n\n return this.sessionManager.create({\n user_agent: options.userAgent,\n ip_address: options.ipAddress,\n realm_id: authorizationCode.realm_id,\n client_id: authorizationCode.client_id,\n sub_kind: authorizationCode.sub_kind,\n sub: authorizationCode.sub,\n });\n }\n}\n"],"mappings":";;;;;;;;;AAmBA,IAAaM,uBAAb,cAA0CF,gBAAAA;CAC5BG;CAEAC;CAEAC;CAEV,YAAYC,KAAkC;EAC1C,MAAM;GACFC,mBAAmBD,IAAIC;GACvBC,gBAAgBF,IAAIE;EACxB,CAAA;EAEA,KAAKL,qBAAqBG,IAAIH;EAC9B,KAAKC,oBAAoBE,IAAIF;EAC7B,KAAKC,gBAAgBC,IAAID;CAC7B;CAEA,MAAMI,QACFC,mBACAC,UAAqC,CAAC,GACJ;EAClC,MAAMC,UAAU,MAAM,KAAKC,eAAeH,mBAAmBC,OAAAA;EAE7D,MAAMG,eAA6C;GAC/CC,YAAYJ,QAAQK;GACpBC,gBAAgBN,QAAQO;GACxBC,YAAYP,QAAQQ;GACpBC,KAAKX,kBAAkBW,OAAOC,KAAAA;GAC9BC,UAAUb,kBAAkBa;GAC5BC,UAAUd,kBAAkBc;GAC5BC,YAAYf,kBAAkBe;GAC9BC,OAAOhB,kBAAkBgB,SAASJ,KAAAA;GAClCK,WAAWjB,kBAAkBiB,aAAaL,KAAAA;EAC9C;EAEA,MAAM,CAACM,aAAaC,sBAAsB,MAAM,KAAKtB,kBAAkBuB,MAAMhB,YAAAA;EAC7E,MAAM,CAACiB,cAAcC,uBAAuB,MAAM,KAAK7B,mBAAmB2B,MAAMhB,YAAAA;EAEhF,MAAMmB,eAAkD;GACpDL;GACAC;GACAE;GACAC;EACJ;EAMA,IACItB,kBAAkBgB,SAClB7B,gBAAgBa,kBAAkBgB,OAAO5B,UAAUoC,OAAO,GAC5D;GAKE,MAAMC,MAAM,MAAM,KAAK9B,cAAc+B,cAAc1B,kBAAkBc,QAAQ;GAC7E,IAAI,CAACW,KACD,MAAMvC,SAASyC,iBAAiB3B,kBAAkBc,UAAUd,kBAAkBe,UAAU;GAG5F,MAAM,CAACa,WAAW,MAAM,KAAKlC,kBAAkB0B,MAAM;IACjDT,KAAKX,kBAAkBW,OAAOC,KAAAA;IAC9BC,UAAUb,kBAAkBa;IAC5BC,UAAUd,kBAAkBc;IAC5BC,YAAYf,kBAAkBe;IAC9BC,OAAOhB,kBAAkBgB,SAASJ,KAAAA;IAClCK,WAAWjB,kBAAkBiB,aAAaL,KAAAA;IAC1C,GAAIZ,kBAAkB6B,QAAQ,EAAEA,OAAO7B,kBAAkB6B,MAAM,IAAI,CAAC;IACpE,GAAI,OAAO7B,kBAAkB8B,cAAc,WAAW,EAAEA,WAAW9B,kBAAkB8B,UAAU,IAAI,CAAC;IACpGC,KAAK7B,QAAQQ;IACbsB,SAAS,MAAM3C,qBAAqB6B,aAAaO,IAAIQ,mBAAmB;GAC5E,CAAA;GAEAV,aAAaK,UAAUA;EAC3B;EAEA,OAAOrC,+BAA+BgC,YAAAA;CAC1C;;;;;;;;;;;;;IAeA,MAAgBpB,eACZH,mBACAC,SACiB;EACjB,IAAID,kBAAkBS,YAAY;GAC9B,MAAMyB,WAAW,MAAM,KAAKpC,eAAeqC,YAAYnC,kBAAkBS,UAAU;GACnF,IACIyB,YACAA,SAASvB,QAAQX,kBAAkBW,OACnCuB,SAASrB,aAAab,kBAAkBa,YACxCqB,SAASpB,aAAad,kBAAkBc,UAC1C;IACEoB,SAASjB,YAAYjB,kBAAkBiB,aAAa;IAEpD,OAAO,KAAKnB,eAAesC,QAAQF,QAAAA;GACvC;EACJ;EAEA,OAAO,KAAKpC,eAAeuC,OAAO;GAC9BhC,YAAYJ,QAAQK;GACpBgC,YAAYrC,QAAQO;GACpBM,UAAUd,kBAAkBc;GAC5BG,WAAWjB,kBAAkBiB;GAC7BJ,UAAUb,kBAAkBa;GAC5BF,KAAKX,kBAAkBW;EAC3B,CAAA;CACJ;AACJ"}
@@ -1,12 +1,31 @@
1
1
  import type { OAuth2TokenGrantResponse, OAuth2TokenPayload } from '@authup/specs';
2
- import type { IOAuth2TokenIssuer, IOAuth2TokenRevoker, IOAuth2TokenVerifier } from '../token/index.ts';
2
+ import type { Logger } from '@authup/server-kit';
3
+ import type { ISessionTokenRepository } from '../session-token/index.ts';
4
+ import type { IOAuth2TokenIssuer, IOAuth2TokenRepository, IOAuth2TokenVerifier } from '../token/index.ts';
3
5
  import { OAuth2BaseGrant } from './base.ts';
4
6
  import type { IOAuth2Grant, OAuth2GrantRunWIthOptions, OAuth2RefreshTokenGrantContext } from './types.ts';
5
7
  export declare class OAuth2RefreshTokenGrant extends OAuth2BaseGrant<string | OAuth2TokenPayload> implements IOAuth2Grant {
6
8
  protected refreshTokenIssuer: IOAuth2TokenIssuer;
7
9
  protected tokenVerifier: IOAuth2TokenVerifier;
8
- protected tokenRevoker: IOAuth2TokenRevoker;
10
+ protected tokenRepository: IOAuth2TokenRepository;
11
+ protected sessionTokenRepository: ISessionTokenRepository;
12
+ protected logger?: Logger;
13
+ protected gracePeriod: number;
9
14
  constructor(ctx: OAuth2RefreshTokenGrantContext);
10
15
  runWith(input: string | OAuth2TokenPayload, options?: OAuth2GrantRunWIthOptions): Promise<OAuth2TokenGrantResponse>;
16
+ /**
17
+ * The grace window (opt-in via `tokenRefreshGracePeriod`) absorbs benign
18
+ * concurrent / multi-tab refreshes of the SAME still-current token. It is
19
+ * scoped to the chain tip: a token whose descendant has already been
20
+ * consumed is a stale ancestor (a real replay), never a grace re-use.
21
+ */
22
+ protected isWithinGraceWindow(jti: string, now: Date): Promise<boolean>;
23
+ /**
24
+ * RFC 6819 §5.2.2.3 reaction strategy — revoke the whole token family
25
+ * (the auth_sessions row) on replay: soft-revoke every session-token row,
26
+ * blocklist their jtis in the cache, and delete the session so its access
27
+ * tokens stop verifying on authup's own API.
28
+ */
29
+ protected revokeFamily(sessionId: string, jti: string, at: string): Promise<void>;
11
30
  }
12
31
  //# sourceMappingURL=refresh-token.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"refresh-token.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/grant-types/refresh-token.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGlF,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACvG,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAC;AAE1G,qBAAa,uBAAwB,SAAQ,eAAe,CAAC,MAAM,GAAG,kBAAkB,CAAE,YAAW,YAAY;IAC7G,SAAS,CAAC,kBAAkB,EAAG,kBAAkB,CAAC;IAElD,SAAS,CAAC,aAAa,EAAG,oBAAoB,CAAC;IAE/C,SAAS,CAAC,YAAY,EAAG,mBAAmB,CAAC;gBAEjC,GAAG,EAAE,8BAA8B;IAYzC,OAAO,CACT,KAAK,EAAE,MAAM,GAAG,kBAAkB,EAClC,OAAO,GAAE,yBAA8B,GACvC,OAAO,CAAC,wBAAwB,CAAC;CAkDxC"}
1
+ {"version":3,"file":"refresh-token.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/grant-types/refresh-token.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAElF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC1G,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAC;AAE1G,qBAAa,uBAAwB,SAAQ,eAAe,CAAC,MAAM,GAAG,kBAAkB,CAAE,YAAW,YAAY;IAC7G,SAAS,CAAC,kBAAkB,EAAG,kBAAkB,CAAC;IAElD,SAAS,CAAC,aAAa,EAAG,oBAAoB,CAAC;IAE/C,SAAS,CAAC,eAAe,EAAG,sBAAsB,CAAC;IAEnD,SAAS,CAAC,sBAAsB,EAAG,uBAAuB,CAAC;IAE3D,SAAS,CAAC,MAAM,CAAC,EAAG,MAAM,CAAC;IAE3B,SAAS,CAAC,WAAW,EAAG,MAAM,CAAC;gBAEnB,GAAG,EAAE,8BAA8B;IAczC,OAAO,CACT,KAAK,EAAE,MAAM,GAAG,kBAAkB,EAClC,OAAO,GAAE,yBAA8B,GACvC,OAAO,CAAC,wBAAwB,CAAC;IA4FrC;;;;;OAKG;cACa,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAI,OAAO,CAAC,OAAO,CAAC;IAqB9E;;;;;OAKG;cACa,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAI,OAAO,CAAC,IAAI,CAAC;CAmB3F"}
@@ -3,12 +3,15 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { OAuth2BaseGrant } from "./base.mjs";
5
5
  import { buildOAuth2BearerTokenResponse } from "../response/bearer.mjs";
6
- import { JWTError } from "@authup/specs";
6
+ import { JWTError, OAuth2GrantError } from "@authup/specs";
7
7
  //#region src/core/oauth2/grant-types/refresh-token.ts
8
8
  var OAuth2RefreshTokenGrant = class extends OAuth2BaseGrant {
9
9
  refreshTokenIssuer;
10
10
  tokenVerifier;
11
- tokenRevoker;
11
+ tokenRepository;
12
+ sessionTokenRepository;
13
+ logger;
14
+ gracePeriod;
12
15
  constructor(ctx) {
13
16
  super({
14
17
  accessTokenIssuer: ctx.accessTokenIssuer,
@@ -16,31 +19,49 @@ var OAuth2RefreshTokenGrant = class extends OAuth2BaseGrant {
16
19
  });
17
20
  this.refreshTokenIssuer = ctx.refreshTokenIssuer;
18
21
  this.tokenVerifier = ctx.tokenVerifier;
19
- this.tokenRevoker = ctx.tokenRevoker;
22
+ this.tokenRepository = ctx.tokenRepository;
23
+ this.sessionTokenRepository = ctx.sessionTokenRepository;
24
+ this.logger = ctx.logger;
25
+ this.gracePeriod = ctx.options?.gracePeriod ?? 0;
20
26
  }
21
27
  async runWith(input, options = {}) {
22
28
  let payload;
23
- if (typeof input === "string") payload = await this.tokenVerifier.verify(input);
29
+ if (typeof input === "string") payload = await this.tokenVerifier.verify(input, { skipActiveCheck: true });
24
30
  else payload = input;
25
- await this.tokenRevoker.revoke(payload);
31
+ if (!payload.jti) throw JWTError.payloadPropertyInvalid("jti");
26
32
  if (!payload.session_id) throw JWTError.payloadPropertyInvalid("session_id");
33
+ const row = await this.sessionTokenRepository.findOneById(payload.jti);
34
+ if (!row || row.kind !== "refresh") throw OAuth2GrantError.invalid("refresh token is unknown");
35
+ if (row.revoked_at) throw OAuth2GrantError.invalid("refresh token has been revoked");
36
+ if (row.session_id !== payload.session_id) throw OAuth2GrantError.invalid("refresh token session mismatch");
37
+ const now = /* @__PURE__ */ new Date();
38
+ const nowISO = now.toISOString();
39
+ if (!await this.sessionTokenRepository.markRefreshConsumed(payload.jti, nowISO)) {
40
+ if (!await this.isWithinGraceWindow(payload.jti, now)) {
41
+ await this.revokeFamily(row.session_id, payload.jti, nowISO);
42
+ throw OAuth2GrantError.invalid("refresh token replay detected; session revoked");
43
+ }
44
+ }
45
+ await this.tokenRepository.setInactive(payload.jti, payload.exp);
27
46
  const session = await this.sessionManager.findOneById(payload.session_id);
28
47
  if (!session) throw JWTError.payloadPropertyInvalid("session_id");
29
48
  await this.sessionManager.verify(session);
30
49
  if (options.userAgent) session.user_agent = options.userAgent;
31
50
  if (options.ipAddress) session.ip_address = options.ipAddress;
32
51
  await this.sessionManager.refresh(session);
33
- const [accessToken, accessTokenPayload] = await this.accessTokenIssuer.issue({
52
+ const [refreshToken, refreshTokenPayload] = await this.refreshTokenIssuer.issue({
34
53
  ...payload,
35
54
  user_agent: session.user_agent,
36
55
  remote_address: session.ip_address,
37
- exp: this.accessTokenIssuer.buildExp()
56
+ exp: this.refreshTokenIssuer.buildExp(),
57
+ parent_id: payload.jti
38
58
  });
39
- const [refreshToken, refreshTokenPayload] = await this.refreshTokenIssuer.issue({
59
+ const [accessToken, accessTokenPayload] = await this.accessTokenIssuer.issue({
40
60
  ...payload,
41
61
  user_agent: session.user_agent,
42
62
  remote_address: session.ip_address,
43
- exp: this.refreshTokenIssuer.buildExp()
63
+ exp: this.accessTokenIssuer.buildExp(),
64
+ refresh_token_id: refreshTokenPayload.jti
44
65
  });
45
66
  return buildOAuth2BearerTokenResponse({
46
67
  accessToken,
@@ -49,6 +70,31 @@ var OAuth2RefreshTokenGrant = class extends OAuth2BaseGrant {
49
70
  refreshTokenPayload
50
71
  });
51
72
  }
73
+ /**
74
+ * The grace window (opt-in via `tokenRefreshGracePeriod`) absorbs benign
75
+ * concurrent / multi-tab refreshes of the SAME still-current token. It is
76
+ * scoped to the chain tip: a token whose descendant has already been
77
+ * consumed is a stale ancestor (a real replay), never a grace re-use.
78
+ */ async isWithinGraceWindow(jti, now) {
79
+ if (this.gracePeriod <= 0) return false;
80
+ const current = await this.sessionTokenRepository.findOneById(jti);
81
+ if (!current || current.revoked_at !== null || current.consumed_at === null || now.getTime() - new Date(current.consumed_at).getTime() > this.gracePeriod * 1e3) return false;
82
+ return !await this.sessionTokenRepository.hasConsumedChild(jti);
83
+ }
84
+ /**
85
+ * RFC 6819 §5.2.2.3 reaction strategy — revoke the whole token family
86
+ * (the auth_sessions row) on replay: soft-revoke every session-token row,
87
+ * blocklist their jtis in the cache, and delete the session so its access
88
+ * tokens stop verifying on authup's own API.
89
+ */ async revokeFamily(sessionId, jti, at) {
90
+ this.logger?.warn("OAuth2 refresh token replay detected; revoking session", {
91
+ session_id: sessionId,
92
+ jti
93
+ });
94
+ const rows = await this.sessionTokenRepository.revokeBySessionId(sessionId, at);
95
+ await Promise.allSettled(rows.map((row) => this.tokenRepository.setInactive(row.id, Math.floor(new Date(row.expires_at).getTime() / 1e3))));
96
+ await this.sessionManager.revoke(sessionId);
97
+ }
52
98
  };
53
99
  //#endregion
54
100
  export { OAuth2RefreshTokenGrant };
@@ -1 +1 @@
1
- {"version":3,"file":"refresh-token.mjs","names":["JWTError","buildOAuth2BearerTokenResponse","OAuth2BaseGrant","OAuth2RefreshTokenGrant","refreshTokenIssuer","tokenVerifier","tokenRevoker","ctx","accessTokenIssuer","sessionManager","runWith","input","options","payload","verify","revoke","session_id","payloadPropertyInvalid","session","findOneById","userAgent","user_agent","ipAddress","ip_address","refresh","accessToken","accessTokenPayload","issue","remote_address","exp","buildExp","refreshToken","refreshTokenPayload"],"sources":["../../../../src/core/oauth2/grant-types/refresh-token.ts"],"sourcesContent":["/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2TokenGrantResponse, OAuth2TokenPayload } from '@authup/specs';\nimport { JWTError } from '@authup/specs';\nimport { buildOAuth2BearerTokenResponse } from '../response/index.ts';\nimport type { IOAuth2TokenIssuer, IOAuth2TokenRevoker, IOAuth2TokenVerifier } from '../token/index.ts';\nimport { OAuth2BaseGrant } from './base.ts';\nimport type { IOAuth2Grant, OAuth2GrantRunWIthOptions, OAuth2RefreshTokenGrantContext } from './types.ts';\n\nexport class OAuth2RefreshTokenGrant extends OAuth2BaseGrant<string | OAuth2TokenPayload> implements IOAuth2Grant {\n protected refreshTokenIssuer : IOAuth2TokenIssuer;\n\n protected tokenVerifier : IOAuth2TokenVerifier;\n\n protected tokenRevoker : IOAuth2TokenRevoker;\n\n constructor(ctx: OAuth2RefreshTokenGrantContext) {\n super({\n accessTokenIssuer: ctx.accessTokenIssuer,\n sessionManager: ctx.sessionManager,\n });\n\n this.refreshTokenIssuer = ctx.refreshTokenIssuer;\n\n this.tokenVerifier = ctx.tokenVerifier;\n this.tokenRevoker = ctx.tokenRevoker;\n }\n\n async runWith(\n input: string | OAuth2TokenPayload,\n options: OAuth2GrantRunWIthOptions = {},\n ) : Promise<OAuth2TokenGrantResponse> {\n let payload : OAuth2TokenPayload;\n if (typeof input === 'string') {\n payload = await this.tokenVerifier.verify(input);\n } else {\n payload = input;\n }\n\n await this.tokenRevoker.revoke(payload);\n\n if (!payload.session_id) {\n throw JWTError.payloadPropertyInvalid('session_id');\n }\n\n const session = await this.sessionManager.findOneById(payload.session_id);\n if (!session) {\n throw JWTError.payloadPropertyInvalid('session_id');\n }\n\n await this.sessionManager.verify(session);\n\n if (options.userAgent) {\n session.user_agent = options.userAgent;\n }\n if (options.ipAddress) {\n session.ip_address = options.ipAddress;\n }\n await this.sessionManager.refresh(session);\n\n const [accessToken, accessTokenPayload] = await this.accessTokenIssuer.issue({\n ...payload,\n user_agent: session.user_agent,\n remote_address: session.ip_address,\n exp: this.accessTokenIssuer.buildExp(),\n });\n\n const [refreshToken, refreshTokenPayload] = await this.refreshTokenIssuer.issue({\n ...payload,\n user_agent: session.user_agent,\n remote_address: session.ip_address,\n exp: this.refreshTokenIssuer.buildExp(),\n });\n\n return buildOAuth2BearerTokenResponse({\n accessToken,\n accessTokenPayload,\n refreshToken,\n refreshTokenPayload,\n });\n }\n}\n"],"mappings":";;;;;;;AAcA,IAAaG,0BAAb,cAA6CD,gBAAAA;CAC/BE;CAEAC;CAEAC;CAEV,YAAYC,KAAqC;EAC7C,MAAM;GACFC,mBAAmBD,IAAIC;GACvBC,gBAAgBF,IAAIE;EACxB,CAAA;EAEA,KAAKL,qBAAqBG,IAAIH;EAE9B,KAAKC,gBAAgBE,IAAIF;EACzB,KAAKC,eAAeC,IAAID;CAC5B;CAEA,MAAMI,QACFC,OACAC,UAAqC,CAAC,GACJ;EAClC,IAAIC;EACJ,IAAI,OAAOF,UAAU,UACjBE,UAAU,MAAM,KAAKR,cAAcS,OAAOH,KAAAA;OAE1CE,UAAUF;EAGd,MAAM,KAAKL,aAAaS,OAAOF,OAAAA;EAE/B,IAAI,CAACA,QAAQG,YACT,MAAMhB,SAASiB,uBAAuB,YAAA;EAG1C,MAAMC,UAAU,MAAM,KAAKT,eAAeU,YAAYN,QAAQG,UAAU;EACxE,IAAI,CAACE,SACD,MAAMlB,SAASiB,uBAAuB,YAAA;EAG1C,MAAM,KAAKR,eAAeK,OAAOI,OAAAA;EAEjC,IAAIN,QAAQQ,WACRF,QAAQG,aAAaT,QAAQQ;EAEjC,IAAIR,QAAQU,WACRJ,QAAQK,aAAaX,QAAQU;EAEjC,MAAM,KAAKb,eAAee,QAAQN,OAAAA;EAElC,MAAM,CAACO,aAAaC,sBAAsB,MAAM,KAAKlB,kBAAkBmB,MAAM;GACzE,GAAGd;GACHQ,YAAYH,QAAQG;GACpBO,gBAAgBV,QAAQK;GACxBM,KAAK,KAAKrB,kBAAkBsB,SAAQ;EACxC,CAAA;EAEA,MAAM,CAACC,cAAcC,uBAAuB,MAAM,KAAK5B,mBAAmBuB,MAAM;GAC5E,GAAGd;GACHQ,YAAYH,QAAQG;GACpBO,gBAAgBV,QAAQK;GACxBM,KAAK,KAAKzB,mBAAmB0B,SAAQ;EACzC,CAAA;EAEA,OAAO7B,+BAA+B;GAClCwB;GACAC;GACAK;GACAC;EACJ,CAAA;CACJ;AACJ"}
1
+ {"version":3,"file":"refresh-token.mjs","names":["JWTError","OAuth2GrantError","buildOAuth2BearerTokenResponse","OAuth2BaseGrant","OAuth2RefreshTokenGrant","refreshTokenIssuer","tokenVerifier","tokenRepository","sessionTokenRepository","logger","gracePeriod","ctx","accessTokenIssuer","sessionManager","options","runWith","input","payload","verify","skipActiveCheck","jti","payloadPropertyInvalid","session_id","row","findOneById","kind","invalid","revoked_at","now","Date","nowISO","toISOString","consumed","markRefreshConsumed","withinGrace","isWithinGraceWindow","revokeFamily","setInactive","exp","session","userAgent","user_agent","ipAddress","ip_address","refresh","refreshToken","refreshTokenPayload","issue","remote_address","buildExp","parent_id","accessToken","accessTokenPayload","refresh_token_id","current","consumed_at","getTime","chainAdvanced","hasConsumedChild","sessionId","at","warn","rows","revokeBySessionId","Promise","allSettled","map","id","Math","floor","expires_at","revoke"],"sources":["../../../../src/core/oauth2/grant-types/refresh-token.ts"],"sourcesContent":["/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2TokenGrantResponse, OAuth2TokenPayload } from '@authup/specs';\nimport { JWTError, OAuth2GrantError } from '@authup/specs';\nimport type { Logger } from '@authup/server-kit';\nimport { buildOAuth2BearerTokenResponse } from '../response/index.ts';\nimport type { ISessionTokenRepository } from '../session-token/index.ts';\nimport type { IOAuth2TokenIssuer, IOAuth2TokenRepository, IOAuth2TokenVerifier } from '../token/index.ts';\nimport { OAuth2BaseGrant } from './base.ts';\nimport type { IOAuth2Grant, OAuth2GrantRunWIthOptions, OAuth2RefreshTokenGrantContext } from './types.ts';\n\nexport class OAuth2RefreshTokenGrant extends OAuth2BaseGrant<string | OAuth2TokenPayload> implements IOAuth2Grant {\n protected refreshTokenIssuer : IOAuth2TokenIssuer;\n\n protected tokenVerifier : IOAuth2TokenVerifier;\n\n protected tokenRepository : IOAuth2TokenRepository;\n\n protected sessionTokenRepository : ISessionTokenRepository;\n\n protected logger? : Logger;\n\n protected gracePeriod : number;\n\n constructor(ctx: OAuth2RefreshTokenGrantContext) {\n super({\n accessTokenIssuer: ctx.accessTokenIssuer,\n sessionManager: ctx.sessionManager,\n });\n\n this.refreshTokenIssuer = ctx.refreshTokenIssuer;\n this.tokenVerifier = ctx.tokenVerifier;\n this.tokenRepository = ctx.tokenRepository;\n this.sessionTokenRepository = ctx.sessionTokenRepository;\n this.logger = ctx.logger;\n this.gracePeriod = ctx.options?.gracePeriod ?? 0;\n }\n\n async runWith(\n input: string | OAuth2TokenPayload,\n options: OAuth2GrantRunWIthOptions = {},\n ) : Promise<OAuth2TokenGrantResponse> {\n let payload : OAuth2TokenPayload;\n if (typeof input === 'string') {\n // The auth_session_tokens row — not the cache blocklist — is the\n // authority for refresh-token validity, so skip the active check.\n payload = await this.tokenVerifier.verify(input, { skipActiveCheck: true });\n } else {\n payload = input;\n }\n\n if (!payload.jti) {\n throw JWTError.payloadPropertyInvalid('jti');\n }\n if (!payload.session_id) {\n throw JWTError.payloadPropertyInvalid('session_id');\n }\n\n const row = await this.sessionTokenRepository.findOneById(payload.jti);\n if (!row || row.kind !== 'refresh') {\n // Row missing = expired-and-swept or a pre-rotation legacy token\n // (hard cutover). Either way the client must re-authenticate.\n throw OAuth2GrantError.invalid('refresh token is unknown');\n }\n if (row.revoked_at) {\n throw OAuth2GrantError.invalid('refresh token has been revoked');\n }\n if (row.session_id !== payload.session_id) {\n // The row is written with the token's own session_id and jti is\n // globally unique, so a mismatch means corruption / jti reuse — fail\n // closed rather than refresh or revoke against the wrong session.\n throw OAuth2GrantError.invalid('refresh token session mismatch');\n }\n\n const now = new Date();\n const nowISO = now.toISOString();\n\n const consumed = await this.sessionTokenRepository.markRefreshConsumed(payload.jti, nowISO);\n if (!consumed) {\n // Lost the atomic consume — either a replay of an already-rotated\n // token, or a benign concurrent-refresh race the grace window\n // absorbs.\n const withinGrace = await this.isWithinGraceWindow(payload.jti, now);\n if (!withinGrace) {\n await this.revokeFamily(row.session_id, payload.jti, nowISO);\n throw OAuth2GrantError.invalid('refresh token replay detected; session revoked');\n }\n }\n\n // Blocklist the presented refresh token in the cache so introspection\n // reports it inactive. Deliberately NOT a DB revoke — that would set\n // revoked_at and break the grace window.\n await this.tokenRepository.setInactive(payload.jti, payload.exp);\n\n const session = await this.sessionManager.findOneById(payload.session_id);\n if (!session) {\n throw JWTError.payloadPropertyInvalid('session_id');\n }\n\n await this.sessionManager.verify(session);\n\n if (options.userAgent) {\n session.user_agent = options.userAgent;\n }\n if (options.ipAddress) {\n session.ip_address = options.ipAddress;\n }\n await this.sessionManager.refresh(session);\n\n const [refreshToken, refreshTokenPayload] = await this.refreshTokenIssuer.issue({\n ...payload,\n user_agent: session.user_agent,\n remote_address: session.ip_address,\n exp: this.refreshTokenIssuer.buildExp(),\n parent_id: payload.jti,\n });\n\n const [accessToken, accessTokenPayload] = await this.accessTokenIssuer.issue({\n ...payload,\n user_agent: session.user_agent,\n remote_address: session.ip_address,\n exp: this.accessTokenIssuer.buildExp(),\n refresh_token_id: refreshTokenPayload.jti,\n });\n\n return buildOAuth2BearerTokenResponse({\n accessToken,\n accessTokenPayload,\n refreshToken,\n refreshTokenPayload,\n });\n }\n\n /**\n * The grace window (opt-in via `tokenRefreshGracePeriod`) absorbs benign\n * concurrent / multi-tab refreshes of the SAME still-current token. It is\n * scoped to the chain tip: a token whose descendant has already been\n * consumed is a stale ancestor (a real replay), never a grace re-use.\n */\n protected async isWithinGraceWindow(jti: string, now: Date) : Promise<boolean> {\n if (this.gracePeriod <= 0) {\n return false;\n }\n\n const current = await this.sessionTokenRepository.findOneById(jti);\n if (\n !current ||\n current.revoked_at !== null ||\n current.consumed_at === null ||\n (now.getTime() - new Date(current.consumed_at).getTime()) > this.gracePeriod * 1_000\n ) {\n return false;\n }\n\n // Grace applies ONLY to the most-recent consumed token: a consumed\n // descendant proves the rotation advanced past this one (stale replay).\n const chainAdvanced = await this.sessionTokenRepository.hasConsumedChild(jti);\n return !chainAdvanced;\n }\n\n /**\n * RFC 6819 §5.2.2.3 reaction strategy — revoke the whole token family\n * (the auth_sessions row) on replay: soft-revoke every session-token row,\n * blocklist their jtis in the cache, and delete the session so its access\n * tokens stop verifying on authup's own API.\n */\n protected async revokeFamily(sessionId: string, jti: string, at: string) : Promise<void> {\n this.logger?.warn('OAuth2 refresh token replay detected; revoking session', {\n session_id: sessionId,\n jti,\n });\n\n // Blocklisting is best-effort (cache) — settle all of them so one cache\n // failure cannot skip the rest or, worse, abort the session delete\n // below (the load-bearing part of the revocation). Pin each TTL to the\n // token's real expiry (unix seconds) so a long-lived refresh token\n // cannot resurface as active via introspection after the fallback 1h.\n const rows = await this.sessionTokenRepository.revokeBySessionId(sessionId, at);\n await Promise.allSettled(rows.map((row) => this.tokenRepository.setInactive(\n row.id,\n Math.floor(new Date(row.expires_at).getTime() / 1_000),\n )));\n\n await this.sessionManager.revoke(sessionId);\n }\n}\n"],"mappings":"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"}