@rekog/mcp-nest 1.9.10 → 2.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (364) hide show
  1. package/README.md +76 -29
  2. package/dist/index.d.ts +0 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +0 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/mcp/decorators/constants.d.ts +1 -0
  7. package/dist/mcp/decorators/constants.d.ts.map +1 -1
  8. package/dist/mcp/decorators/constants.js +2 -1
  9. package/dist/mcp/decorators/constants.js.map +1 -1
  10. package/dist/mcp/decorators/index.d.ts +3 -1
  11. package/dist/mcp/decorators/index.d.ts.map +1 -1
  12. package/dist/mcp/decorators/index.js +3 -1
  13. package/dist/mcp/decorators/index.js.map +1 -1
  14. package/dist/mcp/decorators/mcp-controller.decorator.d.ts +6 -0
  15. package/dist/mcp/decorators/mcp-controller.decorator.d.ts.map +1 -0
  16. package/dist/mcp/decorators/mcp-controller.decorator.js +43 -0
  17. package/dist/mcp/decorators/mcp-controller.decorator.js.map +1 -0
  18. package/dist/mcp/decorators/mcp-message-pattern.d.ts +3 -0
  19. package/dist/mcp/decorators/mcp-message-pattern.d.ts.map +1 -0
  20. package/dist/mcp/decorators/mcp-message-pattern.js +13 -0
  21. package/dist/mcp/decorators/mcp-message-pattern.js.map +1 -0
  22. package/dist/mcp/decorators/prompt.decorator.d.ts +1 -1
  23. package/dist/mcp/decorators/prompt.decorator.d.ts.map +1 -1
  24. package/dist/mcp/decorators/prompt.decorator.js +2 -1
  25. package/dist/mcp/decorators/prompt.decorator.js.map +1 -1
  26. package/dist/mcp/decorators/public.decorator.js.map +1 -1
  27. package/dist/mcp/decorators/raw-request.decorator.d.ts +2 -0
  28. package/dist/mcp/decorators/raw-request.decorator.d.ts.map +1 -0
  29. package/dist/mcp/decorators/raw-request.decorator.js +6 -0
  30. package/dist/mcp/decorators/raw-request.decorator.js.map +1 -0
  31. package/dist/mcp/decorators/resource-template.decorator.d.ts +1 -1
  32. package/dist/mcp/decorators/resource-template.decorator.d.ts.map +1 -1
  33. package/dist/mcp/decorators/resource-template.decorator.js +2 -1
  34. package/dist/mcp/decorators/resource-template.decorator.js.map +1 -1
  35. package/dist/mcp/decorators/resource.decorator.d.ts +1 -1
  36. package/dist/mcp/decorators/resource.decorator.d.ts.map +1 -1
  37. package/dist/mcp/decorators/resource.decorator.js +2 -1
  38. package/dist/mcp/decorators/resource.decorator.js.map +1 -1
  39. package/dist/mcp/decorators/tool.decorator.d.ts +1 -3
  40. package/dist/mcp/decorators/tool.decorator.d.ts.map +1 -1
  41. package/dist/mcp/decorators/tool.decorator.js +2 -1
  42. package/dist/mcp/decorators/tool.decorator.js.map +1 -1
  43. package/dist/mcp/filters/mcp-exception.filter.d.ts +6 -0
  44. package/dist/mcp/filters/mcp-exception.filter.d.ts.map +1 -0
  45. package/dist/mcp/filters/mcp-exception.filter.js +26 -0
  46. package/dist/mcp/filters/mcp-exception.filter.js.map +1 -0
  47. package/dist/mcp/index.d.ts +11 -7
  48. package/dist/mcp/index.d.ts.map +1 -1
  49. package/dist/mcp/index.js +11 -7
  50. package/dist/mcp/index.js.map +1 -1
  51. package/dist/mcp/interfaces/authenticated-user.interface.d.ts +9 -0
  52. package/dist/mcp/interfaces/authenticated-user.interface.d.ts.map +1 -0
  53. package/dist/{authz/interfaces/request-with-user.js → mcp/interfaces/authenticated-user.interface.js} +1 -1
  54. package/dist/mcp/interfaces/authenticated-user.interface.js.map +1 -0
  55. package/dist/mcp/interfaces/dynamic-prompt.interface.d.ts +1 -1
  56. package/dist/mcp/interfaces/dynamic-prompt.interface.d.ts.map +1 -1
  57. package/dist/mcp/interfaces/dynamic-prompt.interface.js.map +1 -1
  58. package/dist/mcp/interfaces/dynamic-resource.interface.d.ts +1 -1
  59. package/dist/mcp/interfaces/dynamic-resource.interface.d.ts.map +1 -1
  60. package/dist/mcp/interfaces/dynamic-resource.interface.js.map +1 -1
  61. package/dist/mcp/interfaces/dynamic-tool.interface.d.ts +1 -1
  62. package/dist/mcp/interfaces/dynamic-tool.interface.d.ts.map +1 -1
  63. package/dist/mcp/interfaces/dynamic-tool.interface.js.map +1 -1
  64. package/dist/mcp/interfaces/index.d.ts +2 -2
  65. package/dist/mcp/interfaces/index.d.ts.map +1 -1
  66. package/dist/mcp/interfaces/index.js +0 -3
  67. package/dist/mcp/interfaces/index.js.map +1 -1
  68. package/dist/mcp/services/tool-authorization.service.d.ts +7 -5
  69. package/dist/mcp/services/tool-authorization.service.d.ts.map +1 -1
  70. package/dist/mcp/services/tool-authorization.service.js +9 -6
  71. package/dist/mcp/services/tool-authorization.service.js.map +1 -1
  72. package/dist/mcp/transport/mcp-context.d.ts +34 -0
  73. package/dist/mcp/transport/mcp-context.d.ts.map +1 -0
  74. package/dist/mcp/transport/mcp-context.js +74 -0
  75. package/dist/mcp/transport/mcp-context.js.map +1 -0
  76. package/dist/mcp/transport/mcp-http-handler.d.ts +7 -0
  77. package/dist/mcp/transport/mcp-http-handler.d.ts.map +1 -0
  78. package/dist/mcp/transport/mcp-http-handler.js +5 -0
  79. package/dist/mcp/transport/mcp-http-handler.js.map +1 -0
  80. package/dist/mcp/transport/mcp-server-options.interface.d.ts +23 -0
  81. package/dist/mcp/transport/mcp-server-options.interface.d.ts.map +1 -0
  82. package/dist/{authz/providers/oauth-provider.interface.js → mcp/transport/mcp-server-options.interface.js} +1 -1
  83. package/dist/mcp/transport/mcp-server-options.interface.js.map +1 -0
  84. package/dist/mcp/transport/mcp-transport.constants.d.ts +19 -0
  85. package/dist/mcp/transport/mcp-transport.constants.d.ts.map +1 -0
  86. package/dist/mcp/transport/mcp-transport.constants.js +21 -0
  87. package/dist/mcp/transport/mcp-transport.constants.js.map +1 -0
  88. package/dist/mcp/transport/mcp-transport.interface.d.ts +17 -0
  89. package/dist/mcp/transport/mcp-transport.interface.d.ts.map +1 -0
  90. package/dist/{authz/interfaces/oauth-common.interface.js → mcp/transport/mcp-transport.interface.js} +1 -1
  91. package/dist/mcp/transport/mcp-transport.interface.js.map +1 -0
  92. package/dist/mcp/transport/mcp.strategy.d.ts +56 -0
  93. package/dist/mcp/transport/mcp.strategy.d.ts.map +1 -0
  94. package/dist/mcp/transport/mcp.strategy.js +446 -0
  95. package/dist/mcp/transport/mcp.strategy.js.map +1 -0
  96. package/dist/mcp/transport/resource-matcher.d.ts +13 -0
  97. package/dist/mcp/transport/resource-matcher.d.ts.map +1 -0
  98. package/dist/mcp/transport/resource-matcher.js +83 -0
  99. package/dist/mcp/transport/resource-matcher.js.map +1 -0
  100. package/dist/mcp/transport/streamable-http.controller.d.ts +16 -0
  101. package/dist/mcp/transport/streamable-http.controller.d.ts.map +1 -0
  102. package/dist/mcp/transport/streamable-http.controller.js +98 -0
  103. package/dist/mcp/transport/streamable-http.controller.js.map +1 -0
  104. package/dist/mcp/transport/transports/index.d.ts +3 -0
  105. package/dist/mcp/transport/transports/index.d.ts.map +1 -0
  106. package/dist/{authz → mcp/transport/transports}/index.js +2 -10
  107. package/dist/mcp/transport/transports/index.js.map +1 -0
  108. package/dist/mcp/transport/transports/read-body.d.ts +3 -0
  109. package/dist/mcp/transport/transports/read-body.d.ts.map +1 -0
  110. package/dist/mcp/transport/transports/read-body.js +32 -0
  111. package/dist/mcp/transport/transports/read-body.js.map +1 -0
  112. package/dist/mcp/transport/transports/stdio.transport.d.ts +9 -0
  113. package/dist/mcp/transport/transports/stdio.transport.d.ts.map +1 -0
  114. package/dist/mcp/transport/transports/stdio.transport.js +27 -0
  115. package/dist/mcp/transport/transports/stdio.transport.js.map +1 -0
  116. package/dist/mcp/transport/transports/streamable-http.transport.d.ts +33 -0
  117. package/dist/mcp/transport/transports/streamable-http.transport.d.ts.map +1 -0
  118. package/dist/mcp/transport/transports/streamable-http.transport.js +216 -0
  119. package/dist/mcp/transport/transports/streamable-http.transport.js.map +1 -0
  120. package/dist/mcp/utils/mcp-logger.factory.d.ts +6 -2
  121. package/dist/mcp/utils/mcp-logger.factory.d.ts.map +1 -1
  122. package/dist/mcp/utils/mcp-logger.factory.js.map +1 -1
  123. package/package.json +3 -66
  124. package/src/index.ts +0 -1
  125. package/src/mcp/decorators/constants.ts +1 -0
  126. package/src/mcp/decorators/index.ts +3 -1
  127. package/src/mcp/decorators/mcp-controller.decorator.ts +126 -0
  128. package/src/mcp/decorators/mcp-message-pattern.ts +38 -0
  129. package/src/mcp/decorators/prompt.decorator.ts +6 -2
  130. package/src/mcp/decorators/public.decorator.ts +3 -3
  131. package/src/mcp/decorators/raw-request.decorator.ts +32 -0
  132. package/src/mcp/decorators/resource-template.decorator.ts +6 -2
  133. package/src/mcp/decorators/resource.decorator.ts +6 -2
  134. package/src/mcp/decorators/tool.decorator.ts +6 -3
  135. package/src/mcp/filters/mcp-exception.filter.ts +47 -0
  136. package/src/mcp/index.ts +13 -7
  137. package/src/mcp/interfaces/authenticated-user.interface.ts +22 -0
  138. package/src/mcp/interfaces/dynamic-prompt.interface.ts +1 -1
  139. package/src/mcp/interfaces/dynamic-resource.interface.ts +1 -1
  140. package/src/mcp/interfaces/dynamic-tool.interface.ts +2 -2
  141. package/src/mcp/interfaces/index.ts +3 -7
  142. package/src/mcp/services/tool-authorization.service.ts +52 -72
  143. package/src/mcp/transport/mcp-context.ts +138 -0
  144. package/src/mcp/transport/mcp-http-handler.ts +32 -0
  145. package/src/mcp/transport/mcp-server-options.interface.ts +75 -0
  146. package/src/mcp/transport/mcp-transport.constants.ts +99 -0
  147. package/src/mcp/transport/mcp-transport.interface.ts +50 -0
  148. package/src/mcp/transport/mcp.strategy.ts +752 -0
  149. package/src/mcp/transport/resource-matcher.ts +107 -0
  150. package/src/mcp/transport/streamable-http.controller.ts +114 -0
  151. package/src/mcp/transport/transports/index.ts +2 -0
  152. package/src/mcp/transport/transports/read-body.ts +39 -0
  153. package/src/mcp/transport/transports/stdio.transport.ts +35 -0
  154. package/src/mcp/transport/transports/streamable-http.transport.ts +384 -0
  155. package/src/mcp/utils/mcp-logger.factory.spec.ts +8 -22
  156. package/src/mcp/utils/mcp-logger.factory.ts +13 -2
  157. package/dist/authz/guards/jwt-auth.guard.d.ts +0 -19
  158. package/dist/authz/guards/jwt-auth.guard.d.ts.map +0 -1
  159. package/dist/authz/guards/jwt-auth.guard.js +0 -108
  160. package/dist/authz/guards/jwt-auth.guard.js.map +0 -1
  161. package/dist/authz/index.d.ts +0 -11
  162. package/dist/authz/index.d.ts.map +0 -1
  163. package/dist/authz/index.js.map +0 -1
  164. package/dist/authz/interfaces/oauth-common.interface.d.ts +0 -21
  165. package/dist/authz/interfaces/oauth-common.interface.d.ts.map +0 -1
  166. package/dist/authz/interfaces/oauth-common.interface.js.map +0 -1
  167. package/dist/authz/interfaces/request-with-user.d.ts +0 -13
  168. package/dist/authz/interfaces/request-with-user.d.ts.map +0 -1
  169. package/dist/authz/interfaces/request-with-user.js.map +0 -1
  170. package/dist/authz/mcp-oauth.controller.d.ts +0 -81
  171. package/dist/authz/mcp-oauth.controller.d.ts.map +0 -1
  172. package/dist/authz/mcp-oauth.controller.js +0 -540
  173. package/dist/authz/mcp-oauth.controller.js.map +0 -1
  174. package/dist/authz/mcp-oauth.module.d.ts +0 -12
  175. package/dist/authz/mcp-oauth.module.d.ts.map +0 -1
  176. package/dist/authz/mcp-oauth.module.js +0 -271
  177. package/dist/authz/mcp-oauth.module.js.map +0 -1
  178. package/dist/authz/providers/azure-ad.provider.d.ts +0 -3
  179. package/dist/authz/providers/azure-ad.provider.d.ts.map +0 -1
  180. package/dist/authz/providers/azure-ad.provider.js +0 -37
  181. package/dist/authz/providers/azure-ad.provider.js.map +0 -1
  182. package/dist/authz/providers/github.provider.d.ts +0 -3
  183. package/dist/authz/providers/github.provider.d.ts.map +0 -1
  184. package/dist/authz/providers/github.provider.js +0 -24
  185. package/dist/authz/providers/github.provider.js.map +0 -1
  186. package/dist/authz/providers/google.provider.d.ts +0 -3
  187. package/dist/authz/providers/google.provider.d.ts.map +0 -1
  188. package/dist/authz/providers/google.provider.js +0 -25
  189. package/dist/authz/providers/google.provider.js.map +0 -1
  190. package/dist/authz/providers/oauth-provider.interface.d.ts +0 -107
  191. package/dist/authz/providers/oauth-provider.interface.d.ts.map +0 -1
  192. package/dist/authz/providers/oauth-provider.interface.js.map +0 -1
  193. package/dist/authz/services/client.service.d.ts +0 -12
  194. package/dist/authz/services/client.service.d.ts.map +0 -1
  195. package/dist/authz/services/client.service.js +0 -81
  196. package/dist/authz/services/client.service.js.map +0 -1
  197. package/dist/authz/services/jwt-token.service.d.ts +0 -37
  198. package/dist/authz/services/jwt-token.service.d.ts.map +0 -1
  199. package/dist/authz/services/jwt-token.service.js +0 -182
  200. package/dist/authz/services/jwt-token.service.js.map +0 -1
  201. package/dist/authz/services/oauth-strategy.service.d.ts +0 -13
  202. package/dist/authz/services/oauth-strategy.service.d.ts.map +0 -1
  203. package/dist/authz/services/oauth-strategy.service.js +0 -71
  204. package/dist/authz/services/oauth-strategy.service.js.map +0 -1
  205. package/dist/authz/stores/memory-store.service.d.ts +0 -27
  206. package/dist/authz/stores/memory-store.service.d.ts.map +0 -1
  207. package/dist/authz/stores/memory-store.service.js +0 -107
  208. package/dist/authz/stores/memory-store.service.js.map +0 -1
  209. package/dist/authz/stores/oauth-store.interface.d.ts +0 -61
  210. package/dist/authz/stores/oauth-store.interface.d.ts.map +0 -1
  211. package/dist/authz/stores/oauth-store.interface.js +0 -5
  212. package/dist/authz/stores/oauth-store.interface.js.map +0 -1
  213. package/dist/authz/stores/typeorm/constants.d.ts +0 -3
  214. package/dist/authz/stores/typeorm/constants.d.ts.map +0 -1
  215. package/dist/authz/stores/typeorm/constants.js +0 -6
  216. package/dist/authz/stores/typeorm/constants.js.map +0 -1
  217. package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts +0 -15
  218. package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts.map +0 -1
  219. package/dist/authz/stores/typeorm/entities/authorization-code.entity.js +0 -69
  220. package/dist/authz/stores/typeorm/entities/authorization-code.entity.js.map +0 -1
  221. package/dist/authz/stores/typeorm/entities/index.d.ts +0 -5
  222. package/dist/authz/stores/typeorm/entities/index.d.ts.map +0 -1
  223. package/dist/authz/stores/typeorm/entities/index.js +0 -12
  224. package/dist/authz/stores/typeorm/entities/index.js.map +0 -1
  225. package/dist/authz/stores/typeorm/entities/oauth-client.entity.d.ts +0 -17
  226. package/dist/authz/stores/typeorm/entities/oauth-client.entity.d.ts.map +0 -1
  227. package/dist/authz/stores/typeorm/entities/oauth-client.entity.js +0 -77
  228. package/dist/authz/stores/typeorm/entities/oauth-client.entity.js.map +0 -1
  229. package/dist/authz/stores/typeorm/entities/oauth-session.entity.d.ts +0 -14
  230. package/dist/authz/stores/typeorm/entities/oauth-session.entity.d.ts.map +0 -1
  231. package/dist/authz/stores/typeorm/entities/oauth-session.entity.js +0 -65
  232. package/dist/authz/stores/typeorm/entities/oauth-session.entity.js.map +0 -1
  233. package/dist/authz/stores/typeorm/entities/user-profile.entity.d.ts +0 -13
  234. package/dist/authz/stores/typeorm/entities/user-profile.entity.d.ts.map +0 -1
  235. package/dist/authz/stores/typeorm/entities/user-profile.entity.js +0 -62
  236. package/dist/authz/stores/typeorm/entities/user-profile.entity.js.map +0 -1
  237. package/dist/authz/stores/typeorm/typeorm-store.service.d.ts +0 -28
  238. package/dist/authz/stores/typeorm/typeorm-store.service.d.ts.map +0 -1
  239. package/dist/authz/stores/typeorm/typeorm-store.service.js +0 -138
  240. package/dist/authz/stores/typeorm/typeorm-store.service.js.map +0 -1
  241. package/dist/mcp/constants/feature-registration.constants.d.ts +0 -7
  242. package/dist/mcp/constants/feature-registration.constants.d.ts.map +0 -1
  243. package/dist/mcp/constants/feature-registration.constants.js +0 -5
  244. package/dist/mcp/constants/feature-registration.constants.js.map +0 -1
  245. package/dist/mcp/decorators/tool-guards.decorator.d.ts +0 -12
  246. package/dist/mcp/decorators/tool-guards.decorator.d.ts.map +0 -1
  247. package/dist/mcp/decorators/tool-guards.decorator.js +0 -13
  248. package/dist/mcp/decorators/tool-guards.decorator.js.map +0 -1
  249. package/dist/mcp/interfaces/mcp-options.interface.d.ts +0 -53
  250. package/dist/mcp/interfaces/mcp-options.interface.d.ts.map +0 -1
  251. package/dist/mcp/interfaces/mcp-options.interface.js +0 -10
  252. package/dist/mcp/interfaces/mcp-options.interface.js.map +0 -1
  253. package/dist/mcp/mcp.module.d.ts +0 -15
  254. package/dist/mcp/mcp.module.d.ts.map +0 -1
  255. package/dist/mcp/mcp.module.js +0 -248
  256. package/dist/mcp/mcp.module.js.map +0 -1
  257. package/dist/mcp/services/handlers/mcp-handler.base.d.ts +0 -117
  258. package/dist/mcp/services/handlers/mcp-handler.base.d.ts.map +0 -1
  259. package/dist/mcp/services/handlers/mcp-handler.base.js +0 -125
  260. package/dist/mcp/services/handlers/mcp-handler.base.js.map +0 -1
  261. package/dist/mcp/services/handlers/mcp-prompts.handler.d.ts +0 -12
  262. package/dist/mcp/services/handlers/mcp-prompts.handler.d.ts.map +0 -1
  263. package/dist/mcp/services/handlers/mcp-prompts.handler.js +0 -98
  264. package/dist/mcp/services/handlers/mcp-prompts.handler.js.map +0 -1
  265. package/dist/mcp/services/handlers/mcp-resources.handler.d.ts +0 -13
  266. package/dist/mcp/services/handlers/mcp-resources.handler.d.ts.map +0 -1
  267. package/dist/mcp/services/handlers/mcp-resources.handler.js +0 -117
  268. package/dist/mcp/services/handlers/mcp-resources.handler.js.map +0 -1
  269. package/dist/mcp/services/handlers/mcp-tools.handler.d.ts +0 -22
  270. package/dist/mcp/services/handlers/mcp-tools.handler.d.ts.map +0 -1
  271. package/dist/mcp/services/handlers/mcp-tools.handler.js +0 -258
  272. package/dist/mcp/services/handlers/mcp-tools.handler.js.map +0 -1
  273. package/dist/mcp/services/mcp-dynamic-registry.service.d.ts +0 -26
  274. package/dist/mcp/services/mcp-dynamic-registry.service.d.ts.map +0 -1
  275. package/dist/mcp/services/mcp-dynamic-registry.service.js +0 -133
  276. package/dist/mcp/services/mcp-dynamic-registry.service.js.map +0 -1
  277. package/dist/mcp/services/mcp-executor.service.d.ts +0 -15
  278. package/dist/mcp/services/mcp-executor.service.d.ts.map +0 -1
  279. package/dist/mcp/services/mcp-executor.service.js +0 -47
  280. package/dist/mcp/services/mcp-executor.service.js.map +0 -1
  281. package/dist/mcp/services/mcp-registry-discovery.service.d.ts +0 -63
  282. package/dist/mcp/services/mcp-registry-discovery.service.d.ts.map +0 -1
  283. package/dist/mcp/services/mcp-registry-discovery.service.js +0 -397
  284. package/dist/mcp/services/mcp-registry-discovery.service.js.map +0 -1
  285. package/dist/mcp/services/mcp-sse.service.d.ts +0 -20
  286. package/dist/mcp/services/mcp-sse.service.d.ts.map +0 -1
  287. package/dist/mcp/services/mcp-sse.service.js +0 -91
  288. package/dist/mcp/services/mcp-sse.service.js.map +0 -1
  289. package/dist/mcp/services/mcp-streamable-http.service.d.ts +0 -32
  290. package/dist/mcp/services/mcp-streamable-http.service.d.ts.map +0 -1
  291. package/dist/mcp/services/mcp-streamable-http.service.js +0 -327
  292. package/dist/mcp/services/mcp-streamable-http.service.js.map +0 -1
  293. package/dist/mcp/services/sse-ping.service.d.ts +0 -23
  294. package/dist/mcp/services/sse-ping.service.d.ts.map +0 -1
  295. package/dist/mcp/services/sse-ping.service.js +0 -99
  296. package/dist/mcp/services/sse-ping.service.js.map +0 -1
  297. package/dist/mcp/transport/sse.controller.factory.d.ts +0 -14
  298. package/dist/mcp/transport/sse.controller.factory.d.ts.map +0 -1
  299. package/dist/mcp/transport/sse.controller.factory.js +0 -67
  300. package/dist/mcp/transport/sse.controller.factory.js.map +0 -1
  301. package/dist/mcp/transport/stdio.service.d.ts +0 -14
  302. package/dist/mcp/transport/stdio.service.d.ts.map +0 -1
  303. package/dist/mcp/transport/stdio.service.js +0 -66
  304. package/dist/mcp/transport/stdio.service.js.map +0 -1
  305. package/dist/mcp/transport/streamable-http.controller.factory.d.ts +0 -14
  306. package/dist/mcp/transport/streamable-http.controller.factory.d.ts.map +0 -1
  307. package/dist/mcp/transport/streamable-http.controller.factory.js +0 -74
  308. package/dist/mcp/transport/streamable-http.controller.factory.js.map +0 -1
  309. package/dist/mcp/utils/capabilities-builder.d.ts +0 -5
  310. package/dist/mcp/utils/capabilities-builder.d.ts.map +0 -1
  311. package/dist/mcp/utils/capabilities-builder.js +0 -25
  312. package/dist/mcp/utils/capabilities-builder.js.map +0 -1
  313. package/dist/mcp/utils/mcp-server.factory.d.ts +0 -6
  314. package/dist/mcp/utils/mcp-server.factory.d.ts.map +0 -1
  315. package/dist/mcp/utils/mcp-server.factory.js +0 -22
  316. package/dist/mcp/utils/mcp-server.factory.js.map +0 -1
  317. package/src/authz/guards/jwt-auth.guard.ts +0 -127
  318. package/src/authz/index.ts +0 -10
  319. package/src/authz/interfaces/oauth-common.interface.ts +0 -21
  320. package/src/authz/interfaces/request-with-user.ts +0 -16
  321. package/src/authz/mcp-oauth.controller.ts +0 -860
  322. package/src/authz/mcp-oauth.module.ts +0 -384
  323. package/src/authz/providers/azure-ad.provider.ts +0 -40
  324. package/src/authz/providers/github.provider.ts +0 -22
  325. package/src/authz/providers/google.provider.ts +0 -23
  326. package/src/authz/providers/oauth-provider.interface.ts +0 -147
  327. package/src/authz/services/client.service.ts +0 -125
  328. package/src/authz/services/jwt-token.service.spec.ts +0 -67
  329. package/src/authz/services/jwt-token.service.ts +0 -188
  330. package/src/authz/services/oauth-strategy.service.ts +0 -64
  331. package/src/authz/stores/memory-store.service.spec.ts +0 -475
  332. package/src/authz/stores/memory-store.service.ts +0 -141
  333. package/src/authz/stores/oauth-store.interface.ts +0 -131
  334. package/src/authz/stores/typeorm/README.md +0 -140
  335. package/src/authz/stores/typeorm/constants.ts +0 -6
  336. package/src/authz/stores/typeorm/entities/authorization-code.entity.ts +0 -41
  337. package/src/authz/stores/typeorm/entities/index.ts +0 -4
  338. package/src/authz/stores/typeorm/entities/oauth-client.entity.ts +0 -53
  339. package/src/authz/stores/typeorm/entities/oauth-session.entity.ts +0 -38
  340. package/src/authz/stores/typeorm/entities/user-profile.entity.ts +0 -46
  341. package/src/authz/stores/typeorm/typeorm-store.service.spec.ts +0 -494
  342. package/src/authz/stores/typeorm/typeorm-store.service.ts +0 -165
  343. package/src/mcp/constants/feature-registration.constants.ts +0 -24
  344. package/src/mcp/decorators/tool-guards.decorator.ts +0 -82
  345. package/src/mcp/interfaces/mcp-options.interface.ts +0 -95
  346. package/src/mcp/mcp.module.ts +0 -349
  347. package/src/mcp/services/handlers/mcp-handler.base.ts +0 -203
  348. package/src/mcp/services/handlers/mcp-prompts.handler.ts +0 -143
  349. package/src/mcp/services/handlers/mcp-resources.handler.ts +0 -183
  350. package/src/mcp/services/handlers/mcp-tools.handler.spec.ts +0 -41
  351. package/src/mcp/services/handlers/mcp-tools.handler.ts +0 -436
  352. package/src/mcp/services/mcp-dynamic-registry.service.ts +0 -236
  353. package/src/mcp/services/mcp-executor.service.ts +0 -64
  354. package/src/mcp/services/mcp-registry-discovery.service.spec.ts +0 -306
  355. package/src/mcp/services/mcp-registry-discovery.service.ts +0 -849
  356. package/src/mcp/services/mcp-sse.service.ts +0 -124
  357. package/src/mcp/services/mcp-streamable-http.service.ts +0 -472
  358. package/src/mcp/services/sse-ping.service.ts +0 -144
  359. package/src/mcp/transport/custom-decorator.spec.ts +0 -75
  360. package/src/mcp/transport/sse.controller.factory.ts +0 -84
  361. package/src/mcp/transport/stdio.service.ts +0 -75
  362. package/src/mcp/transport/streamable-http.controller.factory.ts +0 -80
  363. package/src/mcp/utils/capabilities-builder.ts +0 -43
  364. package/src/mcp/utils/mcp-server.factory.ts +0 -33
@@ -1,860 +0,0 @@
1
- import {
2
- BadRequestException,
3
- Body,
4
- Controller,
5
- Get,
6
- Header,
7
- HttpCode,
8
- Inject,
9
- Logger,
10
- Next,
11
- Post,
12
- Query,
13
- Req,
14
- Res,
15
- } from '@nestjs/common';
16
- import { createHash, randomBytes } from 'crypto';
17
- import type {
18
- Request as ExpressRequest,
19
- NextFunction,
20
- Response,
21
- } from 'express';
22
- import passport from 'passport';
23
- import { normalizeEndpoint } from '../mcp/utils/normalize-endpoint';
24
- import type {
25
- OAuthEndpointConfiguration,
26
- OAuthModuleOptions,
27
- OAuthSession,
28
- OAuthUserProfile,
29
- } from './providers/oauth-provider.interface';
30
- import { ClientService } from './services/client.service';
31
- import { JwtTokenService, TokenPair } from './services/jwt-token.service';
32
- import { OAuthStrategyService } from './services/oauth-strategy.service';
33
- import type { IOAuthStore } from './stores/oauth-store.interface';
34
-
35
- interface OAuthCallbackRequest extends ExpressRequest {
36
- user?: {
37
- profile: OAuthUserProfile;
38
- accessToken: string;
39
- provider: string;
40
- };
41
- }
42
-
43
- // Add this interface to properly type the Express request with raw body
44
- interface RequestWithRawBody extends ExpressRequest {
45
- rawBody?: Buffer;
46
- textBody?: string;
47
- }
48
-
49
- export function createMcpOAuthController(
50
- endpoints: OAuthEndpointConfiguration = {},
51
- options?: {
52
- disableWellKnownProtectedResourceMetadata?: boolean;
53
- disableWellKnownAuthorizationServerMetadata?: boolean;
54
- },
55
- authModuleId?: string,
56
- ) {
57
- // Optional decorator helpers
58
- const OptionalGet = (
59
- path: string | string[] | undefined,
60
- enabled: boolean,
61
- ): MethodDecorator => {
62
- return enabled && path
63
- ? (Get as unknown as (p?: any) => MethodDecorator)(path)
64
- : ((() => {}) as unknown as MethodDecorator);
65
- };
66
- const OptionalHeader = (
67
- name: string,
68
- value: string,
69
- enabled: boolean,
70
- ): MethodDecorator => {
71
- return enabled
72
- ? (Header as unknown as (n: string, v: string) => MethodDecorator)(
73
- name,
74
- value,
75
- )
76
- : ((() => {}) as unknown as MethodDecorator);
77
- };
78
-
79
- @Controller()
80
- class McpOAuthController {
81
- readonly logger = new Logger(McpOAuthController.name);
82
- readonly serverUrl: string;
83
- readonly isProduction: boolean;
84
- readonly options: OAuthModuleOptions;
85
- readonly strategyName: string;
86
-
87
- constructor(
88
- @Inject(
89
- authModuleId
90
- ? `OAUTH_MODULE_OPTIONS_${authModuleId}`
91
- : 'OAUTH_MODULE_OPTIONS',
92
- )
93
- options: OAuthModuleOptions,
94
- @Inject(authModuleId ? `IOAuthStore_${authModuleId}` : 'IOAuthStore')
95
- readonly store: IOAuthStore,
96
- readonly jwtTokenService: JwtTokenService,
97
- readonly clientService: ClientService,
98
- readonly oauthStrategyService: OAuthStrategyService,
99
- ) {
100
- this.serverUrl = options.serverUrl;
101
- this.isProduction = options.cookieSecure;
102
- this.options = options;
103
- this.strategyName = oauthStrategyService.getStrategyName();
104
- }
105
-
106
- /**
107
- * Utility function to parse form-encoded or JSON bodies
108
- * Handles both string (raw form data) and object bodies
109
- */
110
- parseRequestBody(body: any, req?: RequestWithRawBody): Record<string, any> {
111
- // If body is already a parsed object with properties, return it
112
- if (body && typeof body === 'object' && Object.keys(body).length > 0) {
113
- return body;
114
- }
115
-
116
- // If body is a string (raw form data), parse it
117
- if (typeof body === 'string' && body.length > 0) {
118
- const params = new URLSearchParams(body);
119
- const parsedBody: Record<string, any> = {};
120
- for (const [key, value] of params.entries()) {
121
- parsedBody[key] = value;
122
- }
123
- return parsedBody;
124
- }
125
-
126
- // Check if we have a text body stored on the request (from our middleware)
127
- if (req?.textBody) {
128
- const params = new URLSearchParams(req.textBody);
129
- const parsedBody: Record<string, any> = {};
130
- for (const [key, value] of params.entries()) {
131
- parsedBody[key] = value;
132
- }
133
- return parsedBody;
134
- }
135
-
136
- // Check if we have a raw body buffer stored on the request
137
- if (req?.rawBody) {
138
- const bodyString = req.rawBody.toString('utf-8');
139
- if (bodyString) {
140
- const params = new URLSearchParams(bodyString);
141
- const parsedBody: Record<string, any> = {};
142
- for (const [key, value] of params.entries()) {
143
- parsedBody[key] = value;
144
- }
145
- return parsedBody;
146
- }
147
- }
148
-
149
- // Return empty object if no valid body
150
- return {};
151
- }
152
-
153
- /**
154
- * Middleware to capture raw body for form-encoded requests
155
- * This is needed when bodyParser is disabled in the main app
156
- */
157
- captureRawBody(req: RequestWithRawBody, res: Response, next: NextFunction) {
158
- if (
159
- req.headers['content-type']?.includes(
160
- 'application/x-www-form-urlencoded',
161
- )
162
- ) {
163
- let rawBody = '';
164
-
165
- req.on('data', (chunk: Buffer) => {
166
- rawBody += chunk.toString('utf-8');
167
- });
168
-
169
- req.on('end', () => {
170
- req.textBody = rawBody;
171
- // Also parse and set it as body for NestJS
172
- if (rawBody) {
173
- const params = new URLSearchParams(rawBody);
174
- const parsedBody: any = {};
175
- for (const [key, value] of params.entries()) {
176
- parsedBody[key] = value;
177
- }
178
- (req as any).body = parsedBody;
179
- }
180
- next();
181
- });
182
-
183
- req.on('error', (err) => {
184
- this.logger.error('Error reading request body:', err);
185
- next(err);
186
- });
187
- } else {
188
- next();
189
- }
190
- }
191
-
192
- @OptionalGet(
193
- endpoints.wellKnownProtectedResourceMetadata,
194
- !options?.disableWellKnownProtectedResourceMetadata,
195
- )
196
- @OptionalHeader(
197
- 'content-type',
198
- 'application/json',
199
- !options?.disableWellKnownProtectedResourceMetadata,
200
- )
201
- getProtectedResourceMetadata() {
202
- // The issuer URL of your authorization server.
203
- const authorizationServerIssuer = this.options.jwtIssuer;
204
-
205
- // The canonical URI of the MCP server resource itself.
206
- const resourceIdentifier = this.options.resource;
207
-
208
- const metadata = {
209
- /**
210
- * REQUIRED by MCP Spec.
211
- * A list of authorization server issuer URLs that can issue tokens for this resource.
212
- */
213
- authorization_servers: [authorizationServerIssuer],
214
-
215
- /**
216
- * RECOMMENDED by RFC 9728.
217
- * The identifier for this resource server.
218
- */
219
- resource: resourceIdentifier,
220
-
221
- /**
222
- * RECOMMENDED by RFC 9728.
223
- * A list of scopes that this resource server understands.
224
- */
225
- scopes_supported:
226
- this.options.protectedResourceMetadata.scopesSupported,
227
-
228
- /**
229
- * RECOMMENDED by RFC 9728.
230
- * A list of methods clients can use to present the access token.
231
- */
232
- bearer_methods_supported:
233
- this.options.protectedResourceMetadata.bearerMethodsSupported,
234
-
235
- /**
236
- * OPTIONAL but helpful custom metadata.
237
- * Declares which version of the MCP spec this server supports.
238
- */
239
- mcp_versions_supported:
240
- this.options.protectedResourceMetadata.mcpVersionsSupported,
241
- };
242
-
243
- return metadata;
244
- }
245
-
246
- // OAuth endpoints
247
- @OptionalGet(
248
- endpoints.wellKnownAuthorizationServerMetadata,
249
- !options?.disableWellKnownAuthorizationServerMetadata,
250
- )
251
- @OptionalHeader(
252
- 'content-type',
253
- 'application/json',
254
- !options?.disableWellKnownAuthorizationServerMetadata,
255
- )
256
- getAuthorizationServerMetadata() {
257
- return {
258
- issuer: this.serverUrl,
259
- authorization_endpoint: normalizeEndpoint(
260
- `${this.serverUrl}/${endpoints.authorize}`,
261
- ),
262
- token_endpoint: normalizeEndpoint(
263
- `${this.serverUrl}/${endpoints.token}`,
264
- ),
265
- registration_endpoint: normalizeEndpoint(
266
- `${this.serverUrl}/${endpoints.register}`,
267
- ),
268
- response_types_supported:
269
- this.options.authorizationServerMetadata.responseTypesSupported,
270
- response_modes_supported:
271
- this.options.authorizationServerMetadata.responseModesSupported,
272
- grant_types_supported:
273
- this.options.authorizationServerMetadata.grantTypesSupported,
274
- token_endpoint_auth_methods_supported:
275
- this.options.authorizationServerMetadata
276
- .tokenEndpointAuthMethodsSupported,
277
- scopes_supported:
278
- this.options.authorizationServerMetadata.scopesSupported,
279
- revocation_endpoint: normalizeEndpoint(
280
- `${this.serverUrl}/${endpoints?.revoke}`,
281
- ),
282
- code_challenge_methods_supported:
283
- this.options.authorizationServerMetadata
284
- .codeChallengeMethodsSupported,
285
- };
286
- }
287
-
288
- @Post(endpoints.register)
289
- async registerClient(@Body() registrationDto: any) {
290
- return await this.clientService.registerClient(registrationDto);
291
- }
292
-
293
- @Get(endpoints.authorize)
294
- async authorize(
295
- @Query() query: any,
296
- @Req()
297
- req: any,
298
- @Res() res: Response,
299
- @Next() next: NextFunction,
300
- ) {
301
- const {
302
- response_type,
303
- client_id,
304
- redirect_uri,
305
- code_challenge,
306
- code_challenge_method,
307
- state,
308
- scope,
309
- } = query;
310
- const resource = this.options.resource;
311
- if (response_type !== 'code') {
312
- throw new BadRequestException('Only response_type=code is supported');
313
- }
314
-
315
- if (!client_id) {
316
- throw new BadRequestException('Missing required parameters');
317
- }
318
-
319
- // Validate client and redirect URI
320
- const client = await this.clientService.getClient(client_id);
321
- if (!client) {
322
- throw new BadRequestException('Invalid client_id');
323
- }
324
-
325
- const validRedirect = await this.clientService.validateRedirectUri(
326
- client_id,
327
- redirect_uri,
328
- );
329
- if (!validRedirect) {
330
- throw new BadRequestException('Invalid redirect_uri');
331
- }
332
-
333
- // Create OAuth session
334
- const sessionId = randomBytes(32).toString('base64url');
335
- const sessionState = randomBytes(32).toString('base64url');
336
-
337
- const oauthSession: OAuthSession = {
338
- sessionId,
339
- state: sessionState,
340
- clientId: client_id,
341
- redirectUri: redirect_uri,
342
- codeChallenge: code_challenge,
343
- codeChallengeMethod: code_challenge_method || 'plain',
344
- oauthState: state,
345
- scope: scope,
346
- resource,
347
- expiresAt: Date.now() + this.options.oauthSessionExpiresIn,
348
- };
349
-
350
- await this.store.storeOAuthSession(sessionId, oauthSession);
351
-
352
- // Set session cookie
353
- res.cookie('oauth_session', sessionId, {
354
- httpOnly: true,
355
- secure: this.isProduction,
356
- maxAge: this.options.oauthSessionExpiresIn,
357
- });
358
-
359
- // Store state for passport
360
- res.cookie('oauth_state', sessionState, {
361
- httpOnly: true,
362
- secure: this.isProduction,
363
- maxAge: this.options.oauthSessionExpiresIn,
364
- });
365
-
366
- // Redirect to the provider's auth endpoint
367
- passport.authenticate(this.strategyName, {
368
- state: req.cookies?.oauth_state,
369
- })(req, res, next);
370
- }
371
-
372
- @Get(endpoints.callback)
373
- handleProviderCallback(
374
- @Req() req: OAuthCallbackRequest,
375
- @Res() res: Response,
376
- @Next() next: NextFunction,
377
- ) {
378
- // Use a custom callback to handle the authentication result
379
- passport.authenticate(
380
- this.strategyName,
381
- { session: false },
382
- async (err: any, user: any) => {
383
- try {
384
- if (err) {
385
- this.logger.error('OAuth callback error:', err);
386
- throw new BadRequestException('Authentication failed');
387
- }
388
-
389
- if (!user) {
390
- throw new BadRequestException('Authentication failed');
391
- }
392
-
393
- req.user = user;
394
- await this.processAuthenticationSuccess(req, res);
395
- } catch (error) {
396
- next(error);
397
- }
398
- },
399
- )(req, res, next);
400
- }
401
-
402
- async processAuthenticationSuccess(
403
- req: OAuthCallbackRequest,
404
- res: Response,
405
- ) {
406
- const user = req.user;
407
- if (!user) {
408
- throw new BadRequestException('Authentication failed');
409
- }
410
-
411
- const sessionId = req.cookies?.oauth_session;
412
- if (!sessionId) {
413
- throw new BadRequestException('Missing OAuth session');
414
- }
415
-
416
- const session = await this.store.getOAuthSession(sessionId);
417
- if (!session) {
418
- throw new BadRequestException('Invalid or expired OAuth session');
419
- }
420
-
421
- // Verify state
422
- const stateFromCookie = req.cookies?.oauth_state;
423
- if (session.state !== stateFromCookie) {
424
- throw new BadRequestException('Invalid state parameter');
425
- }
426
-
427
- // Generate JWT for UI access
428
- const jwt = this.jwtTokenService.generateUserToken(
429
- user.profile.username,
430
- user.profile,
431
- );
432
-
433
- // Set JWT token as cookie for UI endpoints
434
- res.cookie('auth_token', jwt, {
435
- httpOnly: true,
436
- secure: this.isProduction,
437
- maxAge: this.options.cookieMaxAge,
438
- });
439
-
440
- // Clear temporary cookies
441
- res.clearCookie('oauth_session');
442
- res.clearCookie('oauth_state');
443
-
444
- // Persist user profile and get stable profile_id
445
- const user_profile_id = await this.store.upsertUserProfile(
446
- user.profile,
447
- user.provider,
448
- );
449
-
450
- // Generate authorization code
451
- const authCode = randomBytes(32).toString('base64url');
452
-
453
- // Store the auth code
454
- await this.store.storeAuthCode({
455
- code: authCode,
456
- user_id: user.profile.username,
457
- client_id: session.clientId!,
458
- redirect_uri: session.redirectUri!,
459
- code_challenge: session.codeChallenge!,
460
- code_challenge_method: session.codeChallengeMethod!,
461
- expires_at: Date.now() + this.options.authCodeExpiresIn,
462
- resource: session.resource,
463
- scope: session.scope,
464
- user_profile_id,
465
- });
466
-
467
- // Build redirect URL with authorization code
468
- const redirectUrl = new URL(session.redirectUri!);
469
- redirectUrl.searchParams.set('code', authCode);
470
- if (session.oauthState) {
471
- redirectUrl.searchParams.set('state', session.oauthState);
472
- }
473
-
474
- // Clean up session
475
- await this.store.removeOAuthSession(sessionId);
476
-
477
- res.redirect(redirectUrl.toString());
478
- }
479
-
480
- @Post(endpoints.token)
481
- @Header('content-type', 'application/json')
482
- @Header('Cache-Control', 'no-store')
483
- @Header('Pragma', 'no-cache')
484
- @HttpCode(200)
485
- async exchangeToken(
486
- @Body() body: any,
487
- @Req() req: RequestWithRawBody,
488
- @Res({ passthrough: true }) res: Response,
489
- ): Promise<TokenPair> {
490
- // Apply middleware to capture raw body if needed
491
- const isFormUrlEncoded = req.headers['content-type']?.includes(
492
- 'application/x-www-form-urlencoded',
493
- );
494
- const isBodyEmpty =
495
- !body ||
496
- (typeof body === 'object' &&
497
- Object.keys(body as Record<string, unknown>).length === 0);
498
-
499
- if (isFormUrlEncoded && isBodyEmpty) {
500
- return new Promise((resolve, reject) => {
501
- this.captureRawBody(req, res, (err?: any) => {
502
- if (err) {
503
- reject(
504
- err instanceof Error ? err : new Error(String(err ?? 'error')),
505
- );
506
- return;
507
- }
508
-
509
- // Avoid returning a Promise from the callback; use an IIFE
510
- void (async () => {
511
- try {
512
- // Re-parse the body after middleware has captured it
513
- const parsedBody = this.parseRequestBody(req.body || body, req);
514
- const result = await this.processTokenExchange(parsedBody, req);
515
- resolve(result);
516
- } catch (error) {
517
- reject(
518
- error instanceof Error
519
- ? error
520
- : new Error(String(error ?? 'error')),
521
- );
522
- }
523
- })();
524
- });
525
- });
526
- }
527
-
528
- // Body is already parsed, process directly
529
- const parsedBody = this.parseRequestBody(body, req);
530
- return this.processTokenExchange(parsedBody, req);
531
- }
532
-
533
- async processTokenExchange(
534
- parsedBody: Record<string, any>,
535
- req: RequestWithRawBody,
536
- ): Promise<TokenPair> {
537
- const { grant_type, code, code_verifier, redirect_uri, refresh_token } =
538
- parsedBody;
539
-
540
- // Add debugging to help identify issues
541
- if (!grant_type) {
542
- this.logger.error('Missing grant_type in request body:', {
543
- parsedBodyKeys: Object.keys(parsedBody),
544
- contentType: req.headers['content-type'],
545
- textBody: req.textBody,
546
- parsedBody,
547
- });
548
- throw new BadRequestException('Missing grant_type parameter');
549
- }
550
-
551
- switch (grant_type) {
552
- case 'authorization_code': {
553
- // Extract client credentials based on authentication method
554
- const clientCredentials = this.extractClientCredentials(
555
- req,
556
- parsedBody,
557
- );
558
- return await this.handleAuthorizationCodeGrant(
559
- typeof code === 'string' ? code : String(code ?? ''),
560
- typeof code_verifier === 'string'
561
- ? code_verifier
562
- : String(code_verifier ?? ''),
563
- typeof redirect_uri === 'string'
564
- ? redirect_uri
565
- : String(redirect_uri ?? ''),
566
- clientCredentials,
567
- );
568
- }
569
- case 'refresh_token': {
570
- // For refresh tokens, try to extract client credentials, but allow fallback to token-based extraction
571
- let clientCredentials: { client_id: string; client_secret?: string };
572
- try {
573
- clientCredentials = this.extractClientCredentials(req, parsedBody);
574
- } catch {
575
- // If we can't extract credentials, we'll try to get them from the refresh token
576
- clientCredentials = { client_id: '' }; // Will be filled from token
577
- }
578
- return await this.handleRefreshTokenGrant(
579
- typeof refresh_token === 'string'
580
- ? refresh_token
581
- : String(refresh_token ?? ''),
582
- clientCredentials,
583
- );
584
- }
585
- default:
586
- throw new BadRequestException(
587
- `Unsupported grant_type: ${grant_type}`,
588
- );
589
- }
590
- }
591
-
592
- /**
593
- * Extract client credentials from request based on authentication method
594
- */
595
- extractClientCredentials(
596
- req: RequestWithRawBody,
597
- body: any,
598
- ): { client_id: string; client_secret?: string } {
599
- // Parse the body using the shared utility function
600
- const parsedBody = this.parseRequestBody(body, req);
601
-
602
- // Try client_secret_basic first (Authorization header)
603
- const authHeader = req.headers?.authorization;
604
- if (authHeader && authHeader.startsWith('Basic ')) {
605
- const credentials = Buffer.from(authHeader.slice(6), 'base64').toString(
606
- 'utf-8',
607
- );
608
- const [client_id, client_secret] = credentials.split(':', 2);
609
- if (client_id) {
610
- return { client_id, client_secret };
611
- }
612
- }
613
-
614
- // Try client_secret_post (body parameters)
615
- if (parsedBody.client_id) {
616
- return {
617
- client_id: parsedBody.client_id,
618
- client_secret: parsedBody.client_secret,
619
- };
620
- }
621
-
622
- throw new BadRequestException('Missing client credentials');
623
- }
624
-
625
- /**
626
- * Validate client authentication based on the client's configured method
627
- */
628
- validateClientAuthentication(
629
- client: any,
630
- clientCredentials: { client_id: string; client_secret?: string },
631
- ): void {
632
- if (!client) {
633
- throw new BadRequestException('Invalid client_id');
634
- }
635
-
636
- const { token_endpoint_auth_method } = client;
637
-
638
- switch (token_endpoint_auth_method) {
639
- case 'client_secret_basic':
640
- case 'client_secret_post':
641
- if (!clientCredentials.client_secret) {
642
- throw new BadRequestException(
643
- 'Client secret required for this authentication method',
644
- );
645
- }
646
- if (client.client_secret !== clientCredentials.client_secret) {
647
- throw new BadRequestException('Invalid client credentials');
648
- }
649
- break;
650
-
651
- case 'none':
652
- // Public client - no secret required
653
- if (clientCredentials.client_secret) {
654
- throw new BadRequestException(
655
- 'Client secret not allowed for public clients',
656
- );
657
- }
658
- break;
659
-
660
- default:
661
- throw new BadRequestException(
662
- `Unsupported authentication method: ${token_endpoint_auth_method}`,
663
- );
664
- }
665
- }
666
-
667
- async handleAuthorizationCodeGrant(
668
- code: string,
669
- code_verifier: string,
670
- _redirect_uri: string,
671
- clientCredentials: { client_id: string; client_secret?: string },
672
- ): Promise<TokenPair> {
673
- this.logger.debug('handleAuthorizationCodeGrant - Params:', {
674
- code,
675
- client_id: clientCredentials.client_id,
676
- });
677
-
678
- // Get and validate the authorization code
679
- const authCode = await this.store.getAuthCode(code);
680
- if (!authCode) {
681
- this.logger.error(
682
- 'handleAuthorizationCodeGrant - Invalid authorization code:',
683
- code,
684
- );
685
- throw new BadRequestException('Invalid authorization code');
686
- }
687
- if (authCode.expires_at < Date.now()) {
688
- await this.store.removeAuthCode(code);
689
- this.logger.error(
690
- 'handleAuthorizationCodeGrant - Authorization code expired:',
691
- code,
692
- );
693
- throw new BadRequestException('Authorization code has expired');
694
- }
695
- if (authCode.client_id !== clientCredentials.client_id) {
696
- this.logger.error(
697
- 'handleAuthorizationCodeGrant - Client ID mismatch:',
698
- { expected: authCode.client_id, got: clientCredentials.client_id },
699
- );
700
- throw new BadRequestException('Client ID mismatch');
701
- }
702
-
703
- // Get client and validate authentication
704
- const client = await this.clientService.getClient(
705
- clientCredentials.client_id,
706
- );
707
- this.validateClientAuthentication(client, clientCredentials);
708
- if (authCode.code_challenge) {
709
- const isValid = this.validatePKCE(
710
- code_verifier,
711
- authCode.code_challenge,
712
- authCode.code_challenge_method,
713
- );
714
- if (!isValid) {
715
- this.logger.error(
716
- 'handleAuthorizationCodeGrant - Invalid PKCE verification',
717
- );
718
- throw new BadRequestException('Invalid PKCE verification');
719
- }
720
- }
721
- if (!authCode.resource) {
722
- this.logger.error(
723
- 'handleAuthorizationCodeGrant - No resource associated with code',
724
- );
725
- throw new BadRequestException(
726
- 'Authorization code is not associated with a resource',
727
- );
728
- }
729
-
730
- let userData: Record<string, unknown> | undefined = undefined;
731
- if (authCode.user_profile_id) {
732
- try {
733
- const profile = await this.store.getUserProfileById(
734
- authCode.user_profile_id,
735
- );
736
- if (profile) {
737
- // Avoid circular/large raw payloads if present
738
- userData = { ...profile };
739
- }
740
- } catch (e) {
741
- this.logger.warn('Failed to load user profile for token payload', e);
742
- }
743
- }
744
-
745
- const tokens = this.jwtTokenService.generateTokenPair(
746
- authCode.user_id,
747
- clientCredentials.client_id,
748
- authCode.scope,
749
- authCode.resource,
750
- {
751
- user_profile_id: authCode.user_profile_id,
752
- user_data: userData,
753
- },
754
- );
755
- await this.store.removeAuthCode(code);
756
- this.logger.debug(
757
- 'handleAuthorizationCodeGrant - Token pair generated for user:',
758
- authCode.user_id,
759
- );
760
- return tokens;
761
- }
762
-
763
- async handleRefreshTokenGrant(
764
- refresh_token: string,
765
- clientCredentials: { client_id: string; client_secret?: string },
766
- ): Promise<TokenPair> {
767
- // Verify the refresh token first to get client_id from token if not provided
768
- const payload = this.jwtTokenService.validateToken(refresh_token);
769
- if (!payload || payload.type !== 'refresh') {
770
- throw new BadRequestException('Invalid or expired refresh token');
771
- }
772
-
773
- // Use client_id from token if not provided in credentials
774
- const clientId = clientCredentials.client_id || payload.client_id;
775
- if (!clientId) {
776
- throw new BadRequestException('Unable to determine client_id');
777
- }
778
-
779
- // Get client and validate authentication
780
- const client = await this.clientService.getClient(clientId);
781
-
782
- // For refresh token grants, we can be more lenient with client authentication
783
- // if the token already contains the client_id and the client is public
784
- if (client?.token_endpoint_auth_method !== 'none') {
785
- this.validateClientAuthentication(client, {
786
- ...clientCredentials,
787
- client_id: clientId,
788
- });
789
- }
790
-
791
- // Verify the refresh token belongs to the client
792
- if (payload.client_id !== clientId) {
793
- throw new BadRequestException(
794
- 'Invalid refresh token or token does not belong to this client',
795
- );
796
- }
797
-
798
- let newTokens: TokenPair | null = null;
799
- try {
800
- const payload = this.jwtTokenService.validateToken(refresh_token);
801
- if (!payload || payload.type !== 'refresh') {
802
- throw new BadRequestException('Invalid or expired refresh token');
803
- }
804
-
805
- let userData: Record<string, unknown> | undefined = undefined;
806
- if (payload.user_profile_id) {
807
- try {
808
- const profile = await this.store.getUserProfileById(
809
- payload.user_profile_id,
810
- );
811
- if (profile) userData = { ...profile };
812
- } catch (e) {
813
- this.logger.warn(
814
- 'Failed to load user profile for refreshed token payload',
815
- e,
816
- );
817
- }
818
- }
819
-
820
- newTokens = this.jwtTokenService.generateTokenPair(
821
- payload.sub,
822
- clientId,
823
- payload.scope,
824
- payload.resource,
825
- {
826
- user_profile_id: payload.user_profile_id,
827
- user_data: userData,
828
- },
829
- );
830
- } catch (e) {
831
- this.logger.warn(
832
- 'Refresh flow failed using enriched path, fallback',
833
- e,
834
- );
835
- newTokens = this.jwtTokenService.refreshAccessToken(refresh_token);
836
- }
837
-
838
- if (!newTokens) throw new BadRequestException('Failed to refresh token');
839
- return newTokens;
840
- }
841
-
842
- validatePKCE(
843
- code_verifier: string,
844
- code_challenge: string,
845
- method: string,
846
- ): boolean {
847
- if (method === 'plain') {
848
- return code_verifier === code_challenge;
849
- } else if (method === 'S256') {
850
- const hash = createHash('sha256')
851
- .update(code_verifier)
852
- .digest('base64url');
853
- return hash === code_challenge;
854
- }
855
- return false;
856
- }
857
- }
858
-
859
- return McpOAuthController;
860
- }