@payez/next-mvp 3.0.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 (654) hide show
  1. package/README.md +782 -0
  2. package/dist/api/auth-handler.d.ts +67 -0
  3. package/dist/api/auth-handler.js +397 -0
  4. package/dist/api/index.d.ts +10 -0
  5. package/dist/api/index.js +19 -0
  6. package/dist/api-handlers/account/change-password.d.ts +9 -0
  7. package/dist/api-handlers/account/change-password.js +112 -0
  8. package/dist/api-handlers/account/masked-info.d.ts +2 -0
  9. package/dist/api-handlers/account/masked-info.js +41 -0
  10. package/dist/api-handlers/account/profile.d.ts +3 -0
  11. package/dist/api-handlers/account/profile.js +63 -0
  12. package/dist/api-handlers/account/recovery/initiate.d.ts +2 -0
  13. package/dist/api-handlers/account/recovery/initiate.js +26 -0
  14. package/dist/api-handlers/account/recovery/send-code.d.ts +2 -0
  15. package/dist/api-handlers/account/recovery/send-code.js +28 -0
  16. package/dist/api-handlers/account/recovery/verify-code.d.ts +2 -0
  17. package/dist/api-handlers/account/recovery/verify-code.js +28 -0
  18. package/dist/api-handlers/account/reset-password.d.ts +2 -0
  19. package/dist/api-handlers/account/reset-password.js +26 -0
  20. package/dist/api-handlers/account/send-code.d.ts +24 -0
  21. package/dist/api-handlers/account/send-code.js +60 -0
  22. package/dist/api-handlers/account/update-phone.d.ts +27 -0
  23. package/dist/api-handlers/account/update-phone.js +64 -0
  24. package/dist/api-handlers/account/validate-password.d.ts +17 -0
  25. package/dist/api-handlers/account/validate-password.js +81 -0
  26. package/dist/api-handlers/account/verify-email.d.ts +26 -0
  27. package/dist/api-handlers/account/verify-email.js +106 -0
  28. package/dist/api-handlers/account/verify-sms.d.ts +26 -0
  29. package/dist/api-handlers/account/verify-sms.js +106 -0
  30. package/dist/api-handlers/admin/analytics.d.ts +20 -0
  31. package/dist/api-handlers/admin/analytics.js +379 -0
  32. package/dist/api-handlers/admin/audit.d.ts +20 -0
  33. package/dist/api-handlers/admin/audit.js +214 -0
  34. package/dist/api-handlers/admin/index.d.ts +21 -0
  35. package/dist/api-handlers/admin/index.js +41 -0
  36. package/dist/api-handlers/admin/redis-sessions.d.ts +36 -0
  37. package/dist/api-handlers/admin/redis-sessions.js +204 -0
  38. package/dist/api-handlers/admin/sessions.d.ts +21 -0
  39. package/dist/api-handlers/admin/sessions.js +284 -0
  40. package/dist/api-handlers/admin/site-logs.d.ts +46 -0
  41. package/dist/api-handlers/admin/site-logs.js +318 -0
  42. package/dist/api-handlers/admin/users.d.ts +20 -0
  43. package/dist/api-handlers/admin/users.js +222 -0
  44. package/dist/api-handlers/admin/vibe-data.d.ts +80 -0
  45. package/dist/api-handlers/admin/vibe-data.js +268 -0
  46. package/dist/api-handlers/anon/preferences.d.ts +37 -0
  47. package/dist/api-handlers/anon/preferences.js +96 -0
  48. package/dist/api-handlers/auth/jwks.d.ts +2 -0
  49. package/dist/api-handlers/auth/jwks.js +24 -0
  50. package/dist/api-handlers/auth/login.d.ts +42 -0
  51. package/dist/api-handlers/auth/login.js +178 -0
  52. package/dist/api-handlers/auth/refresh.d.ts +74 -0
  53. package/dist/api-handlers/auth/refresh.js +635 -0
  54. package/dist/api-handlers/auth/signout.d.ts +37 -0
  55. package/dist/api-handlers/auth/signout.js +187 -0
  56. package/dist/api-handlers/auth/status.d.ts +8 -0
  57. package/dist/api-handlers/auth/status.js +26 -0
  58. package/dist/api-handlers/auth/update-session.d.ts +37 -0
  59. package/dist/api-handlers/auth/update-session.js +95 -0
  60. package/dist/api-handlers/auth/validate.d.ts +6 -0
  61. package/dist/api-handlers/auth/validate.js +43 -0
  62. package/dist/api-handlers/auth/verify-code.d.ts +43 -0
  63. package/dist/api-handlers/auth/verify-code.js +94 -0
  64. package/dist/api-handlers/session/refresh-viability.d.ts +14 -0
  65. package/dist/api-handlers/session/refresh-viability.js +39 -0
  66. package/dist/api-handlers/session/viability.d.ts +13 -0
  67. package/dist/api-handlers/session/viability.js +146 -0
  68. package/dist/api-handlers/test/force-expire.d.ts +23 -0
  69. package/dist/api-handlers/test/force-expire.js +65 -0
  70. package/dist/auth/auth-decision.d.ts +39 -0
  71. package/dist/auth/auth-decision.js +182 -0
  72. package/dist/auth/auth-options.d.ts +57 -0
  73. package/dist/auth/auth-options.js +213 -0
  74. package/dist/auth/callbacks/index.d.ts +6 -0
  75. package/dist/auth/callbacks/index.js +12 -0
  76. package/dist/auth/callbacks/jwt.d.ts +45 -0
  77. package/dist/auth/callbacks/jwt.js +305 -0
  78. package/dist/auth/callbacks/session.d.ts +60 -0
  79. package/dist/auth/callbacks/session.js +170 -0
  80. package/dist/auth/callbacks/signin.d.ts +23 -0
  81. package/dist/auth/callbacks/signin.js +44 -0
  82. package/dist/auth/events/index.d.ts +4 -0
  83. package/dist/auth/events/index.js +8 -0
  84. package/dist/auth/events/signout.d.ts +17 -0
  85. package/dist/auth/events/signout.js +32 -0
  86. package/dist/auth/providers/credentials.d.ts +32 -0
  87. package/dist/auth/providers/credentials.js +223 -0
  88. package/dist/auth/providers/index.d.ts +5 -0
  89. package/dist/auth/providers/index.js +21 -0
  90. package/dist/auth/providers/oauth.d.ts +26 -0
  91. package/dist/auth/providers/oauth.js +105 -0
  92. package/dist/auth/route-config.d.ts +66 -0
  93. package/dist/auth/route-config.js +190 -0
  94. package/dist/auth/types/auth-types.d.ts +417 -0
  95. package/dist/auth/types/auth-types.js +53 -0
  96. package/dist/auth/types/index.d.ts +6 -0
  97. package/dist/auth/types/index.js +22 -0
  98. package/dist/auth/unauthenticated-routes.d.ts +1 -0
  99. package/dist/auth/unauthenticated-routes.js +19 -0
  100. package/dist/auth/utils/idp-client.d.ts +94 -0
  101. package/dist/auth/utils/idp-client.js +383 -0
  102. package/dist/auth/utils/index.d.ts +5 -0
  103. package/dist/auth/utils/index.js +21 -0
  104. package/dist/auth/utils/token-utils.d.ts +84 -0
  105. package/dist/auth/utils/token-utils.js +219 -0
  106. package/dist/client/AuthContext.d.ts +19 -0
  107. package/dist/client/AuthContext.js +112 -0
  108. package/dist/client/fetch-with-auth.d.ts +11 -0
  109. package/dist/client/fetch-with-auth.js +44 -0
  110. package/dist/client/fetchWithSession.d.ts +3 -0
  111. package/dist/client/fetchWithSession.js +24 -0
  112. package/dist/client/index.d.ts +9 -0
  113. package/dist/client/index.js +20 -0
  114. package/dist/client/useAnonSession.d.ts +36 -0
  115. package/dist/client/useAnonSession.js +99 -0
  116. package/dist/components/SessionSync.d.ts +13 -0
  117. package/dist/components/SessionSync.js +119 -0
  118. package/dist/components/SignalRHealthCheck.d.ts +10 -0
  119. package/dist/components/SignalRHealthCheck.js +97 -0
  120. package/dist/components/account/UserAvatarMenu.d.ts +20 -0
  121. package/dist/components/account/UserAvatarMenu.js +80 -0
  122. package/dist/components/account/index.d.ts +7 -0
  123. package/dist/components/account/index.js +10 -0
  124. package/dist/components/admin/AlertSettingsTab.d.ts +48 -0
  125. package/dist/components/admin/AlertSettingsTab.js +351 -0
  126. package/dist/components/admin/AnalyticsTab.d.ts +22 -0
  127. package/dist/components/admin/AnalyticsTab.js +167 -0
  128. package/dist/components/admin/DataBrowserTab.d.ts +19 -0
  129. package/dist/components/admin/DataBrowserTab.js +252 -0
  130. package/dist/components/admin/LoggingSettingsTab.d.ts +73 -0
  131. package/dist/components/admin/LoggingSettingsTab.js +339 -0
  132. package/dist/components/admin/SessionsTab.d.ts +37 -0
  133. package/dist/components/admin/SessionsTab.js +165 -0
  134. package/dist/components/admin/StatsTab.d.ts +53 -0
  135. package/dist/components/admin/StatsTab.js +161 -0
  136. package/dist/components/admin/VibeAdminContext.d.ts +32 -0
  137. package/dist/components/admin/VibeAdminContext.js +38 -0
  138. package/dist/components/admin/VibeAdminLayout.d.ts +11 -0
  139. package/dist/components/admin/VibeAdminLayout.js +69 -0
  140. package/dist/components/admin/index.d.ts +29 -0
  141. package/dist/components/admin/index.js +44 -0
  142. package/dist/components/auth/FederatedAuthSection.d.ts +8 -0
  143. package/dist/components/auth/FederatedAuthSection.js +45 -0
  144. package/dist/components/auth/ModeAwareLoginPage.d.ts +10 -0
  145. package/dist/components/auth/ModeAwareLoginPage.js +42 -0
  146. package/dist/components/auth/ModeAwareSignupPage.d.ts +9 -0
  147. package/dist/components/auth/ModeAwareSignupPage.js +78 -0
  148. package/dist/components/auth/TraditionalAuthSection.d.ts +14 -0
  149. package/dist/components/auth/TraditionalAuthSection.js +20 -0
  150. package/dist/components/recovery/CompleteStep.d.ts +5 -0
  151. package/dist/components/recovery/CompleteStep.js +8 -0
  152. package/dist/components/recovery/InitiateRecoveryStep.d.ts +8 -0
  153. package/dist/components/recovery/InitiateRecoveryStep.js +20 -0
  154. package/dist/components/recovery/SelectMethodStep.d.ts +8 -0
  155. package/dist/components/recovery/SelectMethodStep.js +8 -0
  156. package/dist/components/recovery/SetPasswordStep.d.ts +6 -0
  157. package/dist/components/recovery/SetPasswordStep.js +20 -0
  158. package/dist/components/recovery/VerifyCodeStep.d.ts +10 -0
  159. package/dist/components/recovery/VerifyCodeStep.js +24 -0
  160. package/dist/components/reserved/ReservedRecoveryWarning.d.ts +38 -0
  161. package/dist/components/reserved/ReservedRecoveryWarning.js +92 -0
  162. package/dist/components/reserved/ReservedStatusBox.d.ts +30 -0
  163. package/dist/components/reserved/ReservedStatusBox.js +71 -0
  164. package/dist/components/ui/BetaBadge.d.ts +29 -0
  165. package/dist/components/ui/BetaBadge.js +38 -0
  166. package/dist/components/ui/Footer.d.ts +37 -0
  167. package/dist/components/ui/Footer.js +41 -0
  168. package/dist/config/env.d.ts +66 -0
  169. package/dist/config/env.js +57 -0
  170. package/dist/config/logger.d.ts +57 -0
  171. package/dist/config/logger.js +73 -0
  172. package/dist/config/logging-config.d.ts +30 -0
  173. package/dist/config/logging-config.js +122 -0
  174. package/dist/config/unauthenticated-routes.d.ts +17 -0
  175. package/dist/config/unauthenticated-routes.js +24 -0
  176. package/dist/config/vibe-log-transport.d.ts +79 -0
  177. package/dist/config/vibe-log-transport.js +203 -0
  178. package/dist/edge/internal-api-url.d.ts +53 -0
  179. package/dist/edge/internal-api-url.js +63 -0
  180. package/dist/edge/middleware.d.ts +14 -0
  181. package/dist/edge/middleware.js +32 -0
  182. package/dist/hooks/useAuth.d.ts +23 -0
  183. package/dist/hooks/useAuth.js +81 -0
  184. package/dist/hooks/useAuthSettings.d.ts +59 -0
  185. package/dist/hooks/useAuthSettings.js +93 -0
  186. package/dist/hooks/useAvailableProviders.d.ts +45 -0
  187. package/dist/hooks/useAvailableProviders.js +108 -0
  188. package/dist/hooks/usePasswordValidation.d.ts +27 -0
  189. package/dist/hooks/usePasswordValidation.js +102 -0
  190. package/dist/hooks/useProfile.d.ts +15 -0
  191. package/dist/hooks/useProfile.js +59 -0
  192. package/dist/hooks/usePublicAuthSettings.d.ts +56 -0
  193. package/dist/hooks/usePublicAuthSettings.js +131 -0
  194. package/dist/hooks/useSessionExpiration.d.ts +57 -0
  195. package/dist/hooks/useSessionExpiration.js +72 -0
  196. package/dist/hooks/useViabilitySession.d.ts +75 -0
  197. package/dist/hooks/useViabilitySession.js +268 -0
  198. package/dist/index.d.ts +12 -0
  199. package/dist/index.js +54 -0
  200. package/dist/lib/anon-session.d.ts +74 -0
  201. package/dist/lib/anon-session.js +169 -0
  202. package/dist/lib/api-handler.d.ts +123 -0
  203. package/dist/lib/api-handler.js +478 -0
  204. package/dist/lib/app-slug.d.ts +95 -0
  205. package/dist/lib/app-slug.js +172 -0
  206. package/dist/lib/demo-mode.d.ts +6 -0
  207. package/dist/lib/demo-mode.js +16 -0
  208. package/dist/lib/geolocation.d.ts +64 -0
  209. package/dist/lib/geolocation.js +235 -0
  210. package/dist/lib/idp-client-config.d.ts +75 -0
  211. package/dist/lib/idp-client-config.js +351 -0
  212. package/dist/lib/idp-fetch.d.ts +14 -0
  213. package/dist/lib/idp-fetch.js +91 -0
  214. package/dist/lib/internal-api.d.ts +87 -0
  215. package/dist/lib/internal-api.js +122 -0
  216. package/dist/lib/jwt-decode-client.d.ts +10 -0
  217. package/dist/lib/jwt-decode-client.js +46 -0
  218. package/dist/lib/jwt-decode.d.ts +48 -0
  219. package/dist/lib/jwt-decode.js +57 -0
  220. package/dist/lib/nextauth-secret.d.ts +10 -0
  221. package/dist/lib/nextauth-secret.js +104 -0
  222. package/dist/lib/rate-limit-service.d.ts +23 -0
  223. package/dist/lib/rate-limit-service.js +6 -0
  224. package/dist/lib/redis.d.ts +5 -0
  225. package/dist/lib/redis.js +28 -0
  226. package/dist/lib/refresh-token-validator.d.ts +13 -0
  227. package/dist/lib/refresh-token-validator.js +117 -0
  228. package/dist/lib/roles.d.ts +145 -0
  229. package/dist/lib/roles.js +168 -0
  230. package/dist/lib/secret-validation.d.ts +4 -0
  231. package/dist/lib/secret-validation.js +14 -0
  232. package/dist/lib/session-store.d.ts +166 -0
  233. package/dist/lib/session-store.js +537 -0
  234. package/dist/lib/session.d.ts +21 -0
  235. package/dist/lib/session.js +26 -0
  236. package/dist/lib/site-logger.d.ts +214 -0
  237. package/dist/lib/site-logger.js +210 -0
  238. package/dist/lib/standardized-client-api.d.ts +161 -0
  239. package/dist/lib/standardized-client-api.js +786 -0
  240. package/dist/lib/startup-init.d.ts +40 -0
  241. package/dist/lib/startup-init.js +261 -0
  242. package/dist/lib/test-aware-get-token.d.ts +2 -0
  243. package/dist/lib/test-aware-get-token.js +81 -0
  244. package/dist/lib/token-expiry.d.ts +14 -0
  245. package/dist/lib/token-expiry.js +39 -0
  246. package/dist/lib/token-lifecycle.d.ts +52 -0
  247. package/dist/lib/token-lifecycle.js +398 -0
  248. package/dist/lib/types/api-responses.d.ts +128 -0
  249. package/dist/lib/types/api-responses.js +171 -0
  250. package/dist/lib/user-agent-parser.d.ts +50 -0
  251. package/dist/lib/user-agent-parser.js +220 -0
  252. package/dist/logging/api/admin-analytics.d.ts +3 -0
  253. package/dist/logging/api/admin-analytics.js +45 -0
  254. package/dist/logging/api/audit-log.d.ts +3 -0
  255. package/dist/logging/api/audit-log.js +52 -0
  256. package/dist/logging/components/AdminAnalyticsLayout.d.ts +10 -0
  257. package/dist/logging/components/AdminAnalyticsLayout.js +11 -0
  258. package/dist/logging/components/AuditLogViewer.d.ts +7 -0
  259. package/dist/logging/components/AuditLogViewer.js +51 -0
  260. package/dist/logging/components/ErrorMetricsCard.d.ts +7 -0
  261. package/dist/logging/components/ErrorMetricsCard.js +16 -0
  262. package/dist/logging/components/HealthMetricsCard.d.ts +7 -0
  263. package/dist/logging/components/HealthMetricsCard.js +19 -0
  264. package/dist/logging/hooks/useAdminAnalytics.d.ts +24 -0
  265. package/dist/logging/hooks/useAdminAnalytics.js +22 -0
  266. package/dist/logging/hooks/useAuditLog.d.ts +6 -0
  267. package/dist/logging/hooks/useAuditLog.js +25 -0
  268. package/dist/logging/hooks/useErrorMetrics.d.ts +6 -0
  269. package/dist/logging/hooks/useErrorMetrics.js +38 -0
  270. package/dist/logging/hooks/useHealthMetrics.d.ts +6 -0
  271. package/dist/logging/hooks/useHealthMetrics.js +41 -0
  272. package/dist/logging/index.d.ts +11 -0
  273. package/dist/logging/index.js +40 -0
  274. package/dist/logging/types/analytics.d.ts +68 -0
  275. package/dist/logging/types/analytics.js +3 -0
  276. package/dist/logging/types/audit.d.ts +29 -0
  277. package/dist/logging/types/audit.js +2 -0
  278. package/dist/logging/types/index.d.ts +2 -0
  279. package/dist/logging/types/index.js +19 -0
  280. package/dist/middleware/auth-decision.d.ts +33 -0
  281. package/dist/middleware/auth-decision.js +65 -0
  282. package/dist/middleware/create-middleware.d.ts +100 -0
  283. package/dist/middleware/create-middleware.js +445 -0
  284. package/dist/middleware/rbac-check.d.ts +44 -0
  285. package/dist/middleware/rbac-check.js +191 -0
  286. package/dist/middleware/twofa-presets.d.ts +134 -0
  287. package/dist/middleware/twofa-presets.js +175 -0
  288. package/dist/models/DecodedAccessToken.d.ts +17 -0
  289. package/dist/models/DecodedAccessToken.js +2 -0
  290. package/dist/models/SessionModel.d.ts +122 -0
  291. package/dist/models/SessionModel.js +136 -0
  292. package/dist/pages/admin-login/page.d.ts +31 -0
  293. package/dist/pages/admin-login/page.js +83 -0
  294. package/dist/pages/admin-roles/RolesAdminPage.d.ts +15 -0
  295. package/dist/pages/admin-roles/RolesAdminPage.js +78 -0
  296. package/dist/pages/admin-roles/index.d.ts +8 -0
  297. package/dist/pages/admin-roles/index.js +15 -0
  298. package/dist/pages/admin-roles/modals.d.ts +72 -0
  299. package/dist/pages/admin-roles/modals.js +154 -0
  300. package/dist/pages/client-admin/ClientSiteAdminPage.d.ts +79 -0
  301. package/dist/pages/client-admin/ClientSiteAdminPage.js +177 -0
  302. package/dist/pages/client-admin/index.d.ts +32 -0
  303. package/dist/pages/client-admin/index.js +37 -0
  304. package/dist/pages/login/page.d.ts +22 -0
  305. package/dist/pages/login/page.js +239 -0
  306. package/dist/pages/profile/EnhancedProfilePage.d.ts +13 -0
  307. package/dist/pages/profile/EnhancedProfilePage.js +150 -0
  308. package/dist/pages/profile/index.d.ts +8 -0
  309. package/dist/pages/profile/index.js +16 -0
  310. package/dist/pages/profile/page.d.ts +19 -0
  311. package/dist/pages/profile/page.js +47 -0
  312. package/dist/pages/profile/profile-patch.d.ts +1 -0
  313. package/dist/pages/profile/profile-patch.js +281 -0
  314. package/dist/pages/recovery/page.d.ts +1 -0
  315. package/dist/pages/recovery/page.js +142 -0
  316. package/dist/pages/roles/MyRolesPage.d.ts +24 -0
  317. package/dist/pages/roles/MyRolesPage.js +71 -0
  318. package/dist/pages/roles/components.d.ts +63 -0
  319. package/dist/pages/roles/components.js +108 -0
  320. package/dist/pages/roles/index.d.ts +8 -0
  321. package/dist/pages/roles/index.js +19 -0
  322. package/dist/pages/security/EnhancedSecurityPage.d.ts +14 -0
  323. package/dist/pages/security/EnhancedSecurityPage.js +248 -0
  324. package/dist/pages/security/index.d.ts +8 -0
  325. package/dist/pages/security/index.js +16 -0
  326. package/dist/pages/security/page.d.ts +21 -0
  327. package/dist/pages/security/page.js +212 -0
  328. package/dist/pages/security/security-patch.d.ts +1 -0
  329. package/dist/pages/security/security-patch.js +302 -0
  330. package/dist/pages/settings/EnhancedSettingsPage.d.ts +46 -0
  331. package/dist/pages/settings/EnhancedSettingsPage.js +231 -0
  332. package/dist/pages/settings/index.d.ts +8 -0
  333. package/dist/pages/settings/index.js +16 -0
  334. package/dist/pages/settings/page.d.ts +7 -0
  335. package/dist/pages/settings/page.js +26 -0
  336. package/dist/pages/showcase/ShowcasePage.d.ts +13 -0
  337. package/dist/pages/showcase/ShowcasePage.js +140 -0
  338. package/dist/pages/showcase/index.d.ts +12 -0
  339. package/dist/pages/showcase/index.js +17 -0
  340. package/dist/pages/test-env/EmergencyLogoutPage.d.ts +14 -0
  341. package/dist/pages/test-env/EmergencyLogoutPage.js +98 -0
  342. package/dist/pages/test-env/JwtInspectPage.d.ts +14 -0
  343. package/dist/pages/test-env/JwtInspectPage.js +114 -0
  344. package/dist/pages/test-env/RefreshTokenPage.d.ts +15 -0
  345. package/dist/pages/test-env/RefreshTokenPage.js +91 -0
  346. package/dist/pages/test-env/TestEnvPage.d.ts +13 -0
  347. package/dist/pages/test-env/TestEnvPage.js +49 -0
  348. package/dist/pages/test-env/index.d.ts +24 -0
  349. package/dist/pages/test-env/index.js +32 -0
  350. package/dist/pages/verify-code/page.d.ts +30 -0
  351. package/dist/pages/verify-code/page.js +408 -0
  352. package/dist/routes/account/index.d.ts +28 -0
  353. package/dist/routes/account/index.js +71 -0
  354. package/dist/routes/account/masked-info.d.ts +33 -0
  355. package/dist/routes/account/masked-info.js +39 -0
  356. package/dist/routes/account/send-code.d.ts +37 -0
  357. package/dist/routes/account/send-code.js +42 -0
  358. package/dist/routes/account/update-phone.d.ts +13 -0
  359. package/dist/routes/account/update-phone.js +17 -0
  360. package/dist/routes/account/verify-email.d.ts +38 -0
  361. package/dist/routes/account/verify-email.js +43 -0
  362. package/dist/routes/account/verify-sms.d.ts +38 -0
  363. package/dist/routes/account/verify-sms.js +43 -0
  364. package/dist/routes/auth/index.d.ts +19 -0
  365. package/dist/routes/auth/index.js +64 -0
  366. package/dist/routes/auth/logout.d.ts +31 -0
  367. package/dist/routes/auth/logout.js +113 -0
  368. package/dist/routes/auth/nextauth.d.ts +19 -0
  369. package/dist/routes/auth/nextauth.js +72 -0
  370. package/dist/routes/auth/refresh.d.ts +30 -0
  371. package/dist/routes/auth/refresh.js +51 -0
  372. package/dist/routes/auth/session.d.ts +72 -0
  373. package/dist/routes/auth/session.js +180 -0
  374. package/dist/routes/auth/settings.d.ts +25 -0
  375. package/dist/routes/auth/settings.js +55 -0
  376. package/dist/routes/auth/viability.d.ts +52 -0
  377. package/dist/routes/auth/viability.js +201 -0
  378. package/dist/routes/index.d.ts +12 -0
  379. package/dist/routes/index.js +54 -0
  380. package/dist/routes/session/index.d.ts +6 -0
  381. package/dist/routes/session/index.js +10 -0
  382. package/dist/routes/session/refresh-viability.d.ts +16 -0
  383. package/dist/routes/session/refresh-viability.js +20 -0
  384. package/dist/services/signalrActivityService.d.ts +44 -0
  385. package/dist/services/signalrActivityService.js +257 -0
  386. package/dist/stores/authStore.d.ts +154 -0
  387. package/dist/stores/authStore.js +1531 -0
  388. package/dist/theme/ThemeProvider.d.ts +14 -0
  389. package/dist/theme/ThemeProvider.js +28 -0
  390. package/dist/theme/default.d.ts +8 -0
  391. package/dist/theme/default.js +33 -0
  392. package/dist/theme/index.d.ts +15 -0
  393. package/dist/theme/index.js +25 -0
  394. package/dist/theme/types.d.ts +56 -0
  395. package/dist/theme/types.js +8 -0
  396. package/dist/theme/useTheme.d.ts +60 -0
  397. package/dist/theme/useTheme.js +63 -0
  398. package/dist/theme/utils.d.ts +13 -0
  399. package/dist/theme/utils.js +39 -0
  400. package/dist/types/api.d.ts +134 -0
  401. package/dist/types/api.js +44 -0
  402. package/dist/types/auth.d.ts +19 -0
  403. package/dist/types/auth.js +2 -0
  404. package/dist/types/logging.d.ts +42 -0
  405. package/dist/types/logging.js +2 -0
  406. package/dist/types/recovery.d.ts +48 -0
  407. package/dist/types/recovery.js +2 -0
  408. package/dist/types/security.d.ts +1 -0
  409. package/dist/types/security.js +2 -0
  410. package/dist/utils/api.d.ts +85 -0
  411. package/dist/utils/api.js +287 -0
  412. package/dist/utils/circuitBreaker.d.ts +43 -0
  413. package/dist/utils/circuitBreaker.js +91 -0
  414. package/dist/utils/error-message.d.ts +1 -0
  415. package/dist/utils/error-message.js +103 -0
  416. package/dist/utils/layout/reservedSpace.d.ts +59 -0
  417. package/dist/utils/layout/reservedSpace.js +102 -0
  418. package/dist/utils/logout.d.ts +14 -0
  419. package/dist/utils/logout.js +32 -0
  420. package/dist/vibe/client.d.ts +261 -0
  421. package/dist/vibe/client.js +445 -0
  422. package/dist/vibe/errors.d.ts +83 -0
  423. package/dist/vibe/errors.js +146 -0
  424. package/dist/vibe/generic.d.ts +234 -0
  425. package/dist/vibe/generic.js +369 -0
  426. package/dist/vibe/hooks/index.d.ts +169 -0
  427. package/dist/vibe/hooks/index.js +252 -0
  428. package/dist/vibe/index.d.ts +23 -0
  429. package/dist/vibe/index.js +67 -0
  430. package/dist/vibe/sessions.d.ts +161 -0
  431. package/dist/vibe/sessions.js +391 -0
  432. package/dist/vibe/types.d.ts +353 -0
  433. package/dist/vibe/types.js +315 -0
  434. package/package.json +855 -0
  435. package/scripts/check-internal-url-usage.sh +73 -0
  436. package/scripts/dev-broker.ps1 +35 -0
  437. package/scripts/dev-local.ps1 +45 -0
  438. package/src/api/auth-handler.ts +550 -0
  439. package/src/api/index.ts +18 -0
  440. package/src/api-handlers/account/change-password.ts +145 -0
  441. package/src/api-handlers/account/masked-info.ts +45 -0
  442. package/src/api-handlers/account/profile.ts +80 -0
  443. package/src/api-handlers/account/recovery/initiate.ts +23 -0
  444. package/src/api-handlers/account/recovery/send-code.ts +25 -0
  445. package/src/api-handlers/account/recovery/verify-code.ts +25 -0
  446. package/src/api-handlers/account/reset-password.ts +23 -0
  447. package/src/api-handlers/account/send-code.ts +76 -0
  448. package/src/api-handlers/account/update-phone.ts +79 -0
  449. package/src/api-handlers/account/validate-password.ts +118 -0
  450. package/src/api-handlers/account/verify-email.ts +125 -0
  451. package/src/api-handlers/account/verify-sms.ts +125 -0
  452. package/src/api-handlers/admin/analytics.ts +445 -0
  453. package/src/api-handlers/admin/audit.ts +225 -0
  454. package/src/api-handlers/admin/index.ts +59 -0
  455. package/src/api-handlers/admin/redis-sessions.ts +253 -0
  456. package/src/api-handlers/admin/sessions.ts +320 -0
  457. package/src/api-handlers/admin/site-logs.ts +367 -0
  458. package/src/api-handlers/admin/users.ts +244 -0
  459. package/src/api-handlers/admin/vibe-data.ts +326 -0
  460. package/src/api-handlers/anon/preferences.ts +123 -0
  461. package/src/api-handlers/auth/jwks.ts +20 -0
  462. package/src/api-handlers/auth/login.ts +240 -0
  463. package/src/api-handlers/auth/refresh.ts +687 -0
  464. package/src/api-handlers/auth/signout.ts +212 -0
  465. package/src/api-handlers/auth/status.ts +23 -0
  466. package/src/api-handlers/auth/update-session.ts +125 -0
  467. package/src/api-handlers/auth/validate.ts +44 -0
  468. package/src/api-handlers/auth/verify-code.ts +129 -0
  469. package/src/api-handlers/session/refresh-viability.ts +36 -0
  470. package/src/api-handlers/session/viability.ts +166 -0
  471. package/src/api-handlers/test/force-expire.ts +67 -0
  472. package/src/auth/auth-decision.ts +230 -0
  473. package/src/auth/auth-options.ts +237 -0
  474. package/src/auth/callbacks/index.ts +7 -0
  475. package/src/auth/callbacks/jwt.ts +382 -0
  476. package/src/auth/callbacks/session.ts +243 -0
  477. package/src/auth/callbacks/signin.ts +56 -0
  478. package/src/auth/events/index.ts +5 -0
  479. package/src/auth/events/signout.ts +33 -0
  480. package/src/auth/providers/credentials.ts +256 -0
  481. package/src/auth/providers/index.ts +6 -0
  482. package/src/auth/providers/oauth.ts +114 -0
  483. package/src/auth/route-config.ts +220 -0
  484. package/src/auth/types/auth-types.ts +555 -0
  485. package/src/auth/types/index.ts +7 -0
  486. package/src/auth/unauthenticated-routes.ts +3 -0
  487. package/src/auth/utils/idp-client.ts +444 -0
  488. package/src/auth/utils/index.ts +6 -0
  489. package/src/auth/utils/token-utils.ts +244 -0
  490. package/src/client/AuthContext.tsx +140 -0
  491. package/src/client/fetch-with-auth.ts +48 -0
  492. package/src/client/fetchWithSession.ts +21 -0
  493. package/src/client/index.ts +13 -0
  494. package/src/client/useAnonSession.ts +131 -0
  495. package/src/components/SessionSync.tsx +137 -0
  496. package/src/components/SignalRHealthCheck.tsx +131 -0
  497. package/src/components/account/UserAvatarMenu.tsx +217 -0
  498. package/src/components/account/index.ts +8 -0
  499. package/src/components/admin/AlertSettingsTab.tsx +728 -0
  500. package/src/components/admin/AnalyticsTab.tsx +703 -0
  501. package/src/components/admin/DataBrowserTab.tsx +505 -0
  502. package/src/components/admin/LoggingSettingsTab.tsx +665 -0
  503. package/src/components/admin/SessionsTab.tsx +414 -0
  504. package/src/components/admin/StatsTab.tsx +379 -0
  505. package/src/components/admin/VibeAdminContext.tsx +87 -0
  506. package/src/components/admin/VibeAdminLayout.tsx +185 -0
  507. package/src/components/admin/index.ts +59 -0
  508. package/src/components/auth/FederatedAuthSection.tsx +95 -0
  509. package/src/components/auth/ModeAwareLoginPage.tsx +135 -0
  510. package/src/components/auth/ModeAwareSignupPage.tsx +267 -0
  511. package/src/components/auth/TraditionalAuthSection.tsx +99 -0
  512. package/src/components/recovery/CompleteStep.tsx +36 -0
  513. package/src/components/recovery/InitiateRecoveryStep.tsx +68 -0
  514. package/src/components/recovery/SelectMethodStep.tsx +73 -0
  515. package/src/components/recovery/SetPasswordStep.tsx +97 -0
  516. package/src/components/recovery/VerifyCodeStep.tsx +90 -0
  517. package/src/components/reserved/ReservedRecoveryWarning.tsx +160 -0
  518. package/src/components/reserved/ReservedStatusBox.tsx +118 -0
  519. package/src/components/ui/BetaBadge.tsx +58 -0
  520. package/src/components/ui/Footer.tsx +93 -0
  521. package/src/config/env.ts +57 -0
  522. package/src/config/logger.ts +62 -0
  523. package/src/config/logging-config.ts +82 -0
  524. package/src/config/unauthenticated-routes.ts +19 -0
  525. package/src/config/vibe-log-transport.ts +250 -0
  526. package/src/edge/internal-api-url.ts +65 -0
  527. package/src/edge/middleware.ts +42 -0
  528. package/src/hooks/useAuth.ts +115 -0
  529. package/src/hooks/useAuthSettings.ts +97 -0
  530. package/src/hooks/useAvailableProviders.ts +118 -0
  531. package/src/hooks/usePasswordValidation.ts +127 -0
  532. package/src/hooks/useProfile.ts +75 -0
  533. package/src/hooks/usePublicAuthSettings.ts +149 -0
  534. package/src/hooks/useSessionExpiration.ts +102 -0
  535. package/src/hooks/useViabilitySession.ts +335 -0
  536. package/src/index.ts +63 -0
  537. package/src/lib/anon-session.ts +213 -0
  538. package/src/lib/api-handler.ts +625 -0
  539. package/src/lib/app-slug.ts +178 -0
  540. package/src/lib/demo-mode.ts +13 -0
  541. package/src/lib/geolocation.ts +265 -0
  542. package/src/lib/idp-client-config.ts +442 -0
  543. package/src/lib/idp-fetch.ts +101 -0
  544. package/src/lib/internal-api.ts +171 -0
  545. package/src/lib/jwt-decode-client.ts +45 -0
  546. package/src/lib/jwt-decode.ts +83 -0
  547. package/src/lib/nextauth-secret.ts +126 -0
  548. package/src/lib/rate-limit-service.ts +9 -0
  549. package/src/lib/redis.ts +27 -0
  550. package/src/lib/refresh-token-validator.ts +64 -0
  551. package/src/lib/roles.ts +177 -0
  552. package/src/lib/secret-validation.ts +8 -0
  553. package/src/lib/session-store.ts +637 -0
  554. package/src/lib/session.ts +34 -0
  555. package/src/lib/site-logger.ts +245 -0
  556. package/src/lib/standardized-client-api.ts +896 -0
  557. package/src/lib/startup-init.ts +247 -0
  558. package/src/lib/test-aware-get-token.ts +30 -0
  559. package/src/lib/token-expiry.ts +40 -0
  560. package/src/lib/token-lifecycle.ts +477 -0
  561. package/src/lib/types/api-responses.ts +336 -0
  562. package/src/lib/user-agent-parser.ts +252 -0
  563. package/src/logging/api/admin-analytics.ts +51 -0
  564. package/src/logging/api/audit-log.ts +53 -0
  565. package/src/logging/components/AdminAnalyticsLayout.tsx +49 -0
  566. package/src/logging/components/AuditLogViewer.tsx +125 -0
  567. package/src/logging/components/ErrorMetricsCard.tsx +98 -0
  568. package/src/logging/components/HealthMetricsCard.tsx +70 -0
  569. package/src/logging/hooks/useAdminAnalytics.ts +22 -0
  570. package/src/logging/hooks/useAuditLog.ts +24 -0
  571. package/src/logging/hooks/useErrorMetrics.ts +40 -0
  572. package/src/logging/hooks/useHealthMetrics.ts +44 -0
  573. package/src/logging/index.ts +18 -0
  574. package/src/logging/types/analytics.ts +81 -0
  575. package/src/logging/types/audit.ts +31 -0
  576. package/src/logging/types/index.ts +3 -0
  577. package/src/middleware/auth-decision.ts +43 -0
  578. package/src/middleware/create-middleware.ts +626 -0
  579. package/src/middleware/rbac-check.ts +244 -0
  580. package/src/middleware/twofa-presets.ts +224 -0
  581. package/src/models/DecodedAccessToken.ts +17 -0
  582. package/src/models/SessionModel.ts +258 -0
  583. package/src/pages/admin-login/page.tsx +229 -0
  584. package/src/pages/admin-roles/RolesAdminPage.tsx +357 -0
  585. package/src/pages/admin-roles/index.ts +9 -0
  586. package/src/pages/admin-roles/modals.tsx +469 -0
  587. package/src/pages/client-admin/ClientSiteAdminPage.tsx +380 -0
  588. package/src/pages/client-admin/index.ts +33 -0
  589. package/src/pages/login/page.tsx +463 -0
  590. package/src/pages/profile/EnhancedProfilePage.tsx +479 -0
  591. package/src/pages/profile/index.ts +9 -0
  592. package/src/pages/profile/page.tsx +166 -0
  593. package/src/pages/recovery/page.tsx +234 -0
  594. package/src/pages/roles/MyRolesPage.tsx +211 -0
  595. package/src/pages/roles/components.tsx +294 -0
  596. package/src/pages/roles/index.ts +17 -0
  597. package/src/pages/security/EnhancedSecurityPage.tsx +574 -0
  598. package/src/pages/security/index.ts +9 -0
  599. package/src/pages/security/page.tsx +507 -0
  600. package/src/pages/settings/EnhancedSettingsPage.tsx +642 -0
  601. package/src/pages/settings/index.ts +9 -0
  602. package/src/pages/settings/page.tsx +47 -0
  603. package/src/pages/showcase/ShowcasePage.tsx +530 -0
  604. package/src/pages/showcase/index.ts +13 -0
  605. package/src/pages/test-env/EmergencyLogoutPage.tsx +179 -0
  606. package/src/pages/test-env/JwtInspectPage.tsx +418 -0
  607. package/src/pages/test-env/RefreshTokenPage.tsx +155 -0
  608. package/src/pages/test-env/TestEnvPage.tsx +116 -0
  609. package/src/pages/test-env/index.ts +25 -0
  610. package/src/pages/verify-code/page.tsx +648 -0
  611. package/src/routes/account/index.ts +32 -0
  612. package/src/routes/account/masked-info.ts +37 -0
  613. package/src/routes/account/send-code.ts +40 -0
  614. package/src/routes/account/update-phone.ts +13 -0
  615. package/src/routes/account/verify-email.ts +41 -0
  616. package/src/routes/account/verify-sms.ts +41 -0
  617. package/src/routes/auth/index.ts +23 -0
  618. package/src/routes/auth/logout.ts +127 -0
  619. package/src/routes/auth/nextauth.ts +71 -0
  620. package/src/routes/auth/refresh.ts +54 -0
  621. package/src/routes/auth/session.ts +193 -0
  622. package/src/routes/auth/settings.ts +75 -0
  623. package/src/routes/auth/viability.ts +220 -0
  624. package/src/routes/index.ts +18 -0
  625. package/src/routes/session/index.ts +7 -0
  626. package/src/routes/session/refresh-viability.ts +17 -0
  627. package/src/services/signalrActivityService.ts +258 -0
  628. package/src/stores/authStore.ts +1904 -0
  629. package/src/templates/instrumentation.ts +41 -0
  630. package/src/theme/ThemeProvider.tsx +39 -0
  631. package/src/theme/default.ts +33 -0
  632. package/src/theme/index.ts +31 -0
  633. package/src/theme/types.ts +69 -0
  634. package/src/theme/useTheme.ts +57 -0
  635. package/src/theme/utils.ts +40 -0
  636. package/src/types/api.ts +13 -0
  637. package/src/types/auth.d.ts +15 -0
  638. package/src/types/auth.ts +22 -0
  639. package/src/types/logging.ts +11 -0
  640. package/src/types/next-auth.d.ts +15 -0
  641. package/src/types/recovery.ts +54 -0
  642. package/src/types/security.ts +1 -0
  643. package/src/utils/api.ts +353 -0
  644. package/src/utils/circuitBreaker.ts +40 -0
  645. package/src/utils/error-message.ts +108 -0
  646. package/src/utils/layout/reservedSpace.ts +124 -0
  647. package/src/utils/logout.ts +30 -0
  648. package/src/vibe/client.ts +590 -0
  649. package/src/vibe/errors.ts +185 -0
  650. package/src/vibe/generic.ts +429 -0
  651. package/src/vibe/hooks/index.ts +367 -0
  652. package/src/vibe/index.ts +121 -0
  653. package/src/vibe/sessions.ts +551 -0
  654. package/src/vibe/types.ts +577 -0
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Session Viability Check API Handler for `@payez/next-mvp`
3
+ *
4
+ * This API route is called by the middleware to securely check if a session is valid.
5
+ */
6
+
7
+ import { NextRequest, NextResponse } from 'next/server';
8
+ import { getSession } from '../../lib/session-store';
9
+ import { getToken } from 'next-auth/jwt';
10
+ import { isInitializationFailed, ensureInitialized } from '../../lib/startup-init';
11
+ import { getJwtCookieName } from '../../lib/app-slug';
12
+ import { getIDPClientConfig } from '../../lib/idp-client-config';
13
+
14
+ /**
15
+ * Get NextAuth secret from IDP config (cached).
16
+ * NEVER use process.env.NEXTAUTH_SECRET directly - it may not be set.
17
+ */
18
+ async function getNextAuthSecret(): Promise<string> {
19
+ const config = await getIDPClientConfig();
20
+ return config.nextAuthSecret || '';
21
+ }
22
+
23
+ export async function GET(req: NextRequest) {
24
+ try {
25
+ // Ensure initialization is complete
26
+ if (!process.env.NEXTAUTH_SECRET) {
27
+ try {
28
+ await ensureInitialized();
29
+ } catch (error) {
30
+ // Initialization failed - return 503
31
+ console.error('[API Viability] Initialization failed - returning 503');
32
+ return NextResponse.json(
33
+ {
34
+ error: 'Service Unavailable',
35
+ message: 'Authentication service is not properly configured',
36
+ code: 'AUTH_NOT_INITIALIZED'
37
+ },
38
+ { status: 503 }
39
+ );
40
+ }
41
+ }
42
+
43
+ // Double-check after initialization attempt
44
+ if (isInitializationFailed()) {
45
+ console.error('[API Viability] Initialization failed - returning 503');
46
+ return NextResponse.json(
47
+ {
48
+ error: 'Service Unavailable',
49
+ message: 'Authentication service is not properly configured',
50
+ code: 'AUTH_NOT_INITIALIZED'
51
+ },
52
+ { status: 503 }
53
+ );
54
+ }
55
+
56
+ // Get secret from IDP config (same source as session.ts and token-lifecycle.ts)
57
+ const secret = await getNextAuthSecret();
58
+ if (!secret) {
59
+ console.error('[API Viability] NEXTAUTH_SECRET not available from IDP config');
60
+ return NextResponse.json(
61
+ {
62
+ error: 'Service Unavailable',
63
+ message: 'Authentication service is not properly configured',
64
+ code: 'AUTH_NOT_INITIALIZED'
65
+ },
66
+ { status: 503 }
67
+ );
68
+ }
69
+
70
+ // getToken is the recommended way to get the JWT from a request
71
+ const cookieName = getJwtCookieName();
72
+ const token = await getToken({ req, secret, cookieName });
73
+
74
+ // Debug logging to diagnose AKS-specific issues
75
+ if (!token) {
76
+ const cookieHeader = req.headers.get('cookie') || '';
77
+ const hasCookie = cookieHeader.includes(cookieName);
78
+ const cookieMatch = cookieHeader.match(new RegExp(`${cookieName}=([^;]*)`));
79
+ const cookieValue = cookieMatch ? cookieMatch[1] : null;
80
+ console.warn('[VIABILITY] getToken returned null:', {
81
+ cookieName,
82
+ hasCookie,
83
+ cookieValueLength: cookieValue?.length || 0,
84
+ cookieValuePreview: cookieValue ? cookieValue.substring(0, 30) + '...' : 'EMPTY',
85
+ secretLength: secret.length,
86
+ secretPreview: secret ? secret.substring(0, 10) + '...' : 'EMPTY',
87
+ });
88
+ }
89
+
90
+ // Support both field names: sessionToken (auth.ts JWT) and redisSessionId (legacy)
91
+ const sessionToken = (token?.sessionToken || token?.redisSessionId) as string | undefined;
92
+ if (token && sessionToken) {
93
+ const sessionData = await getSession(sessionToken);
94
+ if (sessionData) {
95
+ // The session exists in Redis
96
+
97
+ // Check if access token is expired (for middleware decision-making)
98
+ const accessTokenExpires = sessionData.idpAccessTokenExpires || 0;
99
+ const accessTokenExpired = accessTokenExpires < Date.now();
100
+
101
+ // Get requires2FA from cached client config (not session)
102
+ // This is a client-wide setting from the broker handshake
103
+ let requires2FA = true; // Default to true for security
104
+ try {
105
+ const cachedConfig = await getIDPClientConfig();
106
+ requires2FA = cachedConfig.authSettings?.require2FA ?? true;
107
+ } catch (e) {
108
+ console.warn('[API Viability] Could not get client config, defaulting requires2FA to true');
109
+ }
110
+
111
+ // CRITICAL: Check if MFA has expired (2FA TTL enforcement)
112
+ // The session may have mfaVerified=true from days ago, but if mfaExpiresAt
113
+ // has passed, we must treat 2FA as incomplete to force re-verification.
114
+ const mfaExpiresAt = sessionData.mfaExpiresAt || 0;
115
+ const mfaExpired = mfaExpiresAt > 0 && mfaExpiresAt < Date.now();
116
+ // Check both field names for compatibility (mfaVerified is the normalized name)
117
+ const sessionMfaComplete = sessionData.mfaVerified ?? (sessionData as any).twoFactorComplete ?? false;
118
+ const effectiveTwoFactorComplete = sessionMfaComplete && !mfaExpired;
119
+
120
+ console.log('[VIABILITY] Session 2FA check:', {
121
+ sessionToken: sessionToken.substring(0, 8) + '...',
122
+ mfaVerified: sessionData.mfaVerified,
123
+ twoFactorComplete: (sessionData as any).twoFactorComplete,
124
+ sessionMfaComplete,
125
+ mfaExpired,
126
+ effectiveTwoFactorComplete,
127
+ });
128
+
129
+ if (mfaExpired && sessionMfaComplete) {
130
+ console.warn('[API Viability] MFA expired - forcing 2FA re-verification', {
131
+ mfaExpiresAt: new Date(mfaExpiresAt).toISOString(),
132
+ now: new Date().toISOString(),
133
+ hoursExpiredAgo: ((Date.now() - mfaExpiresAt) / (1000 * 60 * 60)).toFixed(1)
134
+ });
135
+ }
136
+
137
+ const response = {
138
+ authenticated: true,
139
+ sessionToken, // Include token for middleware tracking
140
+ // 2FA fields - critical for middleware redirect logic
141
+ requires2FA, // From cached client config (client-wide setting)
142
+ twoFactorComplete: effectiveTwoFactorComplete, // From session, BUT respects MFA TTL
143
+ // Token status for refresh decisions
144
+ accessTokenExpired,
145
+ hasRefreshToken: !!sessionData.idpRefreshToken
146
+ };
147
+ return NextResponse.json(response);
148
+ }
149
+
150
+ // CRITICAL: Cookie exists but Redis session is missing (stale cookie state)
151
+ // Return sessionToken so middleware can detect this and clear the stale cookie
152
+ console.warn('[VIABILITY] Stale cookie detected - session not in Redis');
153
+ return NextResponse.json({
154
+ authenticated: false,
155
+ sessionToken // Include token to enable stale cookie detection
156
+ });
157
+ }
158
+
159
+ // If there's no token at all, it's not authenticated
160
+ return NextResponse.json({ authenticated: false });
161
+
162
+ } catch (error) {
163
+ console.error('[API Viability] Error checking session viability:', error);
164
+ return NextResponse.json({ authenticated: false }, { status: 500 });
165
+ }
166
+ }
@@ -0,0 +1,67 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { getToken } from 'next-auth/jwt';
3
+ import { getSession, updateSession } from '../../lib/session-store';
4
+ import { getJwtCookieName } from '../../lib/app-slug';
5
+
6
+ /**
7
+ * Force-expire access token for testing refresh flow.
8
+ *
9
+ * Sets the access token expiry to 2 minutes in the past,
10
+ * which will trigger a refresh on the next API call.
11
+ *
12
+ * Usage in consuming app:
13
+ * ```typescript
14
+ * // app/api/test/force-expire/route.ts
15
+ * export { POST } from '@payez/next-mvp/api-handlers/test/force-expire';
16
+ * ```
17
+ */
18
+ export const POST = async (req: NextRequest) => {
19
+ try {
20
+ const secret = process.env.NEXTAUTH_SECRET;
21
+ if (!secret) {
22
+ return NextResponse.json({ success: false, error: 'NEXTAUTH_SECRET not configured' }, { status: 500 });
23
+ }
24
+
25
+ const cookieName = getJwtCookieName();
26
+ const token = await getToken({ req, secret, cookieName });
27
+
28
+ let sessionToken = token?.redisSessionId as string | undefined;
29
+ if (!sessionToken) {
30
+ const headerSessionToken = req.headers.get('x-session-token') || req.headers.get('X-Session-Token');
31
+ if (headerSessionToken) {
32
+ sessionToken = headerSessionToken;
33
+ } else {
34
+ console.warn('[TEST_EXPIRE] No session token in JWT cookie or X-Session-Token header');
35
+ return NextResponse.json({ success: false, error: 'No session token' }, { status: 401 });
36
+ }
37
+ }
38
+
39
+ const session = await getSession(sessionToken);
40
+ if (!session) {
41
+ return NextResponse.json({ success: false, error: 'Session not found' }, { status: 404 });
42
+ }
43
+
44
+ const now = Date.now();
45
+ const forced = now - (2 * 60 * 1000); // two minutes ago
46
+ const prev = session.idpAccessTokenExpires || null;
47
+
48
+ await updateSession(sessionToken, { idpAccessTokenExpires: forced });
49
+
50
+ console.log('[TEST_EXPIRE] Forced access token expiry for session', {
51
+ sessionToken: sessionToken.substring(0, 8) + '...',
52
+ previous: prev ? new Date(prev).toISOString() : null,
53
+ newExpiry: new Date(forced).toISOString()
54
+ });
55
+
56
+ return NextResponse.json({
57
+ success: true,
58
+ previous: prev,
59
+ previousIso: prev ? new Date(prev).toISOString() : null,
60
+ newExpiry: forced,
61
+ newExpiryIso: new Date(forced).toISOString()
62
+ });
63
+ } catch (e) {
64
+ console.error('[TEST_EXPIRE] Error:', e);
65
+ return NextResponse.json({ success: false, error: e instanceof Error ? e.message : String(e) }, { status: 500 });
66
+ }
67
+ };
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Auth Decision Engine - Pure function for middleware auth flow
3
+ *
4
+ * This module provides a deterministic decision tree for authentication middleware.
5
+ * All auth flow logic is centralized here for testability and maintainability.
6
+ */
7
+
8
+ // Input types for the decision engine
9
+ export interface AuthContext {
10
+ pathname: string;
11
+ isPublicRoute: boolean;
12
+ isLoginPage: boolean;
13
+ searchParams: URLSearchParams;
14
+ sessionPointer: {
15
+ exists: boolean;
16
+ sessionToken?: string;
17
+ expired?: boolean;
18
+ };
19
+ sessionStatus: {
20
+ exists: boolean | null; // null = check failed/timeout
21
+ forceInvalid: boolean | null; // null = check failed/timeout
22
+ requires2FA: boolean;
23
+ twoFactorComplete: boolean;
24
+ };
25
+ circuitBreakerOpen: boolean;
26
+ }
27
+
28
+ // Output types for the decision engine
29
+ export type AuthAction =
30
+ | { type: 'allow' }
31
+ | { type: 'redirect'; location: string; reason: string; clearCookies?: boolean }
32
+ | { type: 'service_error'; reason: string };
33
+
34
+ /**
35
+ * Main decision function - pure, testable, deterministic
36
+ */
37
+ export function makeAuthDecision(context: AuthContext): AuthAction {
38
+ const {
39
+ pathname,
40
+ isPublicRoute,
41
+ isLoginPage,
42
+ searchParams,
43
+ sessionPointer,
44
+ sessionStatus,
45
+ circuitBreakerOpen
46
+ } = context;
47
+
48
+ // SAFEGUARD: Never use auth pages as callback URLs to prevent redirect loops
49
+ const safeCallbackUrl = pathname.startsWith('/account-auth/') ? '/' : pathname;
50
+
51
+ // Public routes are allowed, but we need to check login page separately
52
+ if (isPublicRoute && !isLoginPage) {
53
+ // For non-login public routes, check if authenticated user needs 2FA
54
+ if (sessionPointer.exists && sessionStatus.exists && sessionStatus.requires2FA && !sessionStatus.twoFactorComplete) {
55
+ // Skip redirect for verify-code page
56
+ if (pathname === '/account-auth/verify-code') {
57
+ return { type: 'allow' };
58
+ }
59
+ }
60
+ return { type: 'allow' };
61
+ }
62
+
63
+ // Circuit breaker open - redirect to login with service unavailable
64
+ if (circuitBreakerOpen) {
65
+ if (isLoginPage) {
66
+ return { type: 'allow' }; // Let them see login page
67
+ }
68
+ return {
69
+ type: 'redirect',
70
+ location: '/account-auth/login?error=ServiceUnavailable&reason=CircuitBreakerOpen',
71
+ reason: 'CircuitBreakerOpen',
72
+ clearCookies: true
73
+ };
74
+ }
75
+
76
+ // No session pointer (JWT cookie) - need to login
77
+ if (!sessionPointer.exists) {
78
+ if (isLoginPage) {
79
+ return { type: 'allow' };
80
+ }
81
+ // Redirect root to configured URL for unauthenticated users
82
+ if (pathname === '/') {
83
+ const unauthUrl = process.env.UNAUTHENTICATED_REDIRECT_URL || '/account-auth/login';
84
+ return {
85
+ type: 'redirect',
86
+ location: unauthUrl,
87
+ reason: 'unauthenticated_root_redirect'
88
+ };
89
+ }
90
+ return {
91
+ type: 'redirect',
92
+ location: `/account-auth/login?callbackUrl=${encodeURIComponent(safeCallbackUrl)}`,
93
+ reason: 'no_session_pointer'
94
+ };
95
+ }
96
+
97
+ // Redis/service errors - can't verify session
98
+ if (sessionStatus.exists === null || sessionStatus.forceInvalid === null) {
99
+ return {
100
+ type: 'service_error',
101
+ reason: 'redis_unavailable'
102
+ };
103
+ }
104
+
105
+ // Session force invalidated - need fresh login
106
+ if (sessionStatus.forceInvalid) {
107
+ if (isLoginPage) {
108
+ return { type: 'allow' };
109
+ }
110
+ return {
111
+ type: 'redirect',
112
+ location: `/account-auth/login?callbackUrl=${encodeURIComponent(safeCallbackUrl)}&reason=force_invalidated`,
113
+ reason: 'force_invalidated',
114
+ clearCookies: true
115
+ };
116
+ }
117
+
118
+ // Stale session (cookie exists but not in Redis) - need fresh login
119
+ if (!sessionStatus.exists) {
120
+ if (isLoginPage) {
121
+ return { type: 'allow' };
122
+ }
123
+ return {
124
+ type: 'redirect',
125
+ location: `/account-auth/login?callbackUrl=${encodeURIComponent(safeCallbackUrl)}&reason=stale_session`,
126
+ reason: 'stale_session',
127
+ clearCookies: true
128
+ };
129
+ }
130
+
131
+ // PRIORITIZE 2FA: If session exists and 2FA is required but not complete, handle this before token-expired logic
132
+ if (sessionStatus.requires2FA && !sessionStatus.twoFactorComplete) {
133
+ console.log('[MIDDLEWARE-DECISION] 2FA required but not complete', {
134
+ pathname,
135
+ isLoginPage,
136
+ sessionExists: sessionStatus.exists,
137
+ sessionToken: sessionPointer.sessionToken?.substring(0, 8) + '...'
138
+ });
139
+
140
+ // Already on the 2FA page
141
+ if (pathname === '/account-auth/verify-code') {
142
+ console.log('[MIDDLEWARE-DECISION] Already on verify-code page, allowing');
143
+ return { type: 'allow' };
144
+ }
145
+ // If user is on the login page, send them to verify-code with the original callback
146
+ if (isLoginPage) {
147
+ const callbackUrl = searchParams.get('callbackUrl') || '/';
148
+ // CRITICAL FIX: Never use auth pages as callback URLs
149
+ const safeCallbackUrl = callbackUrl.startsWith('/account-auth/') ? '/' : callbackUrl;
150
+ console.log('[MIDDLEWARE-DECISION] On login page with 2FA incomplete, redirecting to verify-code', {
151
+ originalCallback: callbackUrl,
152
+ safeCallback: safeCallbackUrl,
153
+ originalUrl: pathname
154
+ });
155
+ return {
156
+ type: 'redirect',
157
+ location: `/account-auth/verify-code?callbackUrl=${encodeURIComponent(safeCallbackUrl)}`,
158
+ reason: '2fa_required_login_redirect'
159
+ };
160
+ }
161
+ // For protected routes, allow middleware to proceed (it may refresh tokens); pages will enforce 2FA
162
+ console.log('[MIDDLEWARE-DECISION] Protected route with incomplete 2FA, allowing middleware to handle');
163
+ return { type: 'allow' };
164
+ }
165
+
166
+ // Token expired - redirect to login (let NextAuth handle refresh)
167
+ if (sessionPointer.expired) {
168
+ if (isLoginPage) {
169
+ return { type: 'allow' };
170
+ }
171
+ return {
172
+ type: 'redirect',
173
+ location: `/account-auth/login?callbackUrl=${encodeURIComponent(safeCallbackUrl)}&error=SessionExpired`,
174
+ reason: 'token_expired'
175
+ };
176
+ }
177
+
178
+ // Authenticated root path should land on dashboards
179
+ if (pathname === '/') {
180
+ return {
181
+ type: 'redirect',
182
+ location: '/',
183
+ reason: 'authenticated_root_redirect'
184
+ };
185
+ }
186
+
187
+ // Valid session but 2FA required and not complete - more intelligent handling
188
+ if (sessionStatus.requires2FA && !sessionStatus.twoFactorComplete) {
189
+ if (pathname === '/account-auth/verify-code') {
190
+ return { type: 'allow' }; // Already on 2FA page
191
+ }
192
+
193
+ // For login page, redirect to 2FA with original callback
194
+ if (isLoginPage) {
195
+ const callbackUrl = searchParams.get('callbackUrl') || '/';
196
+ // CRITICAL FIX: Never use auth pages as callback URLs
197
+ const safeCallbackUrl = callbackUrl.startsWith('/account-auth/') ? '/' : callbackUrl;
198
+ return {
199
+ type: 'redirect',
200
+ location: `/account-auth/verify-code?callbackUrl=${encodeURIComponent(safeCallbackUrl)}`,
201
+ reason: '2fa_required'
202
+ };
203
+ }
204
+
205
+ // For protected routes:
206
+ // - If access token is expired and we have a valid refresh token, let middleware handle refresh first
207
+ // - Only redirect to verify-code if access token is still valid or refresh failed
208
+ // - Allow middleware to pass - it will either refresh successfully or handle redirect appropriately
209
+ return { type: 'allow' };
210
+ }
211
+
212
+ // Authenticated user on login page - redirect to dashboard or callback
213
+ if (isLoginPage) {
214
+ const callbackUrl = searchParams.get('callbackUrl') || '/';
215
+ // CRITICAL FIX: Never redirect back to login page (prevents infinite loop)
216
+ const safeCallbackUrl = callbackUrl.startsWith('/account-auth/') ? '/' : callbackUrl;
217
+ console.log('[MIDDLEWARE-DECISION] Authenticated user on login page, redirecting', {
218
+ originalCallback: callbackUrl,
219
+ safeCallback: safeCallbackUrl
220
+ });
221
+ return {
222
+ type: 'redirect',
223
+ location: safeCallbackUrl,
224
+ reason: 'already_authenticated'
225
+ };
226
+ }
227
+
228
+ // All checks passed - allow access
229
+ return { type: 'allow' };
230
+ }
@@ -0,0 +1,237 @@
1
+ /**
2
+ * NextAuth Configuration (Refactored)
3
+ *
4
+ * This is the composition layer that wires together all auth modules.
5
+ * Individual logic lives in dedicated modules:
6
+ * - providers/ - Credentials and OAuth provider builders
7
+ * - callbacks/ - JWT, session, signIn callbacks
8
+ * - events/ - SignOut event handler
9
+ * - utils/ - Token utilities, IDP client
10
+ * - types/ - Type definitions
11
+ *
12
+ * CARGO CULT PATTERNS REMOVED:
13
+ * ============================
14
+ * The original auth-options.ts (1186 lines) had several anti-patterns that
15
+ * added complexity without benefit:
16
+ *
17
+ * 1. CALLBACK CONCURRENCY PROTECTION (removed)
18
+ * - shouldExecuteCallback() / markCallbackComplete()
19
+ * - A debouncing mechanism that tried to prevent callbacks from running
20
+ * too frequently. NextAuth already handles this properly.
21
+ * - Added complexity, caused race condition bugs, and leaked memory
22
+ * (Map entries never cleaned up).
23
+ *
24
+ * 2. SESSION RESTORATION (removed)
25
+ * - attemptSessionRestoration()
26
+ * - Tried to restore sessions by calling refresh endpoint from JWT callback.
27
+ * - Created circular dependencies and made debugging impossible.
28
+ * - Clean approach: Session missing = user re-authenticates. Simple.
29
+ *
30
+ * 3. VARIABLE NAME SOUP (normalized in Phase 3)
31
+ * - accessToken vs idpAccessToken vs oauthAccessToken
32
+ * - twoFactorComplete vs mfaVerified vs requiresTwoFactor
33
+ * - sessionToken vs redisSessionId
34
+ * - Now: Clear prefixes (idp*, oauth*, mfa*) with documented meanings.
35
+ *
36
+ * 4. INLINE EVERYTHING (modularized in Phase 2)
37
+ * - All logic was in one giant file with no separation of concerns.
38
+ * - Now: Each module has one job and can be tested independently.
39
+ *
40
+ * @version 2.0.0
41
+ * @since auth-refactor-2026-01
42
+ */
43
+
44
+ import type { NextAuthOptions } from 'next-auth';
45
+ import type { Provider } from 'next-auth/providers/index';
46
+ import { encode as defaultEncode, decode as defaultDecode } from 'next-auth/jwt';
47
+ import { getIDPClientConfig, type IDPClientConfig } from '../lib/idp-client-config';
48
+ import {
49
+ getSessionCookieName,
50
+ getSecureSessionCookieName,
51
+ getCsrfCookieName,
52
+ getSecureCsrfCookieName,
53
+ getCallbackUrlCookieName,
54
+ } from '../lib/app-slug';
55
+
56
+ // Module imports
57
+ import { createCredentialsProvider, buildOAuthProviders } from './providers';
58
+ import { jwtCallback, sessionCallback, signInCallback } from './callbacks';
59
+ import { handleSignOut } from './events';
60
+
61
+ // ============================================================================
62
+ // ENVIRONMENT HELPERS
63
+ // ============================================================================
64
+
65
+ /**
66
+ * Get AUTH_ISSUER_URL for JWT issuer claim.
67
+ * Required for SSO across apps.
68
+ */
69
+ function getAuthIssuerUrl(): string {
70
+ const url = process.env.AUTH_ISSUER_URL;
71
+ if (!url) {
72
+ throw new Error('AUTH_ISSUER_URL environment variable is REQUIRED');
73
+ }
74
+ return url;
75
+ }
76
+
77
+ // ============================================================================
78
+ // BASE AUTH OPTIONS
79
+ // ============================================================================
80
+
81
+ /**
82
+ * Base NextAuth configuration.
83
+ * Use getAuthOptions() for dynamic provider loading from IDP.
84
+ */
85
+ export const authOptions: NextAuthOptions = {
86
+ // Session uses JWT strategy - JWT contains only redisSessionId
87
+ session: {
88
+ strategy: 'jwt',
89
+ maxAge: 30 * 24 * 60 * 60, // 30 days default, overridden by IDP config
90
+ },
91
+
92
+ // Custom JWT handling for SSO issuer
93
+ jwt: {
94
+ encode: async (params) => {
95
+ try {
96
+ const issuer = getAuthIssuerUrl();
97
+ console.log('[JWT_ENCODE] Encoding token:', {
98
+ hasToken: !!params.token,
99
+ hasSecret: !!params.secret,
100
+ secretLength: params.secret?.length || 0,
101
+ issuer,
102
+ tokenKeys: params.token ? Object.keys(params.token) : [],
103
+ });
104
+ const encoded = await defaultEncode({
105
+ ...params,
106
+ secret: params.secret,
107
+ token: {
108
+ ...params.token,
109
+ iss: issuer,
110
+ },
111
+ });
112
+ console.log('[JWT_ENCODE] Success, encoded length:', encoded?.length || 0);
113
+ return encoded;
114
+ } catch (error) {
115
+ console.error('[JWT_ENCODE] FAILED:', error);
116
+ throw error;
117
+ }
118
+ },
119
+ decode: async (params) => {
120
+ const decoded = await defaultDecode(params);
121
+ if (decoded?.iss && decoded.iss !== getAuthIssuerUrl()) {
122
+ console.error('[JWT] Invalid issuer. Expected:', getAuthIssuerUrl(), 'Got:', decoded.iss);
123
+ return null; // Hard enforcement - reject mismatched issuers
124
+ }
125
+ return decoded;
126
+ },
127
+ },
128
+
129
+ // Cookie configuration for multi-app support
130
+ // In production, use __Secure- prefixed cookie names for enhanced security
131
+ cookies: {
132
+ sessionToken: {
133
+ name: process.env.NODE_ENV === 'production' ? getSecureSessionCookieName() : getSessionCookieName(),
134
+ options: {
135
+ httpOnly: true,
136
+ sameSite: 'lax',
137
+ path: '/',
138
+ secure: process.env.NODE_ENV === 'production',
139
+ },
140
+ },
141
+ csrfToken: {
142
+ name: process.env.NODE_ENV === 'production' ? getSecureCsrfCookieName() : getCsrfCookieName(),
143
+ options: {
144
+ httpOnly: true,
145
+ sameSite: 'lax',
146
+ path: '/',
147
+ secure: process.env.NODE_ENV === 'production',
148
+ },
149
+ },
150
+ callbackUrl: {
151
+ name: getCallbackUrlCookieName(),
152
+ options: {
153
+ sameSite: 'lax',
154
+ path: '/',
155
+ secure: process.env.NODE_ENV === 'production',
156
+ },
157
+ },
158
+ },
159
+
160
+ // Providers - credentials only in base, OAuth added dynamically
161
+ providers: [createCredentialsProvider()],
162
+
163
+ // Callbacks wired to modular implementations
164
+ callbacks: {
165
+ jwt: jwtCallback,
166
+ session: sessionCallback as any, // Type cast needed for NextAuth compatibility
167
+ signIn: signInCallback,
168
+ },
169
+
170
+ // Events
171
+ events: {
172
+ signOut: handleSignOut,
173
+ },
174
+
175
+ // Custom pages
176
+ pages: {
177
+ signIn: '/account-auth/login',
178
+ error: '/account-auth/login',
179
+ },
180
+
181
+ debug: false,
182
+ };
183
+
184
+ // ============================================================================
185
+ // DYNAMIC AUTH OPTIONS (WITH IDP OAUTH PROVIDERS)
186
+ // ============================================================================
187
+
188
+ let cachedAuthOptions: NextAuthOptions | null = null;
189
+ let authOptionsPromise: Promise<NextAuthOptions> | null = null;
190
+
191
+ /**
192
+ * Get auth options with dynamically loaded OAuth providers from IDP.
193
+ * Uses caching to avoid rebuilding on every request.
194
+ */
195
+ export async function getAuthOptions(): Promise<NextAuthOptions> {
196
+ if (cachedAuthOptions) {
197
+ return cachedAuthOptions;
198
+ }
199
+
200
+ if (authOptionsPromise) {
201
+ return authOptionsPromise;
202
+ }
203
+
204
+ authOptionsPromise = buildDynamicAuthOptions();
205
+ cachedAuthOptions = await authOptionsPromise;
206
+ authOptionsPromise = null;
207
+
208
+ return cachedAuthOptions;
209
+ }
210
+
211
+ /**
212
+ * Build auth options with dynamic OAuth providers from IDP.
213
+ */
214
+ async function buildDynamicAuthOptions(): Promise<NextAuthOptions> {
215
+ const idpConfig = await getIDPClientConfig();
216
+ const oauthProviders = buildOAuthProviders(idpConfig);
217
+
218
+ return {
219
+ ...authOptions,
220
+ secret: idpConfig.nextAuthSecret || process.env.NEXTAUTH_SECRET,
221
+ session: {
222
+ ...authOptions.session,
223
+ maxAge: idpConfig.authSettings?.rememberMeDays
224
+ ? idpConfig.authSettings.rememberMeDays * 24 * 60 * 60
225
+ : 30 * 24 * 60 * 60,
226
+ },
227
+ providers: [createCredentialsProvider(), ...oauthProviders],
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Clear cached auth options (when IDP config changes).
233
+ */
234
+ export function clearAuthOptionsCache(): void {
235
+ cachedAuthOptions = null;
236
+ authOptionsPromise = null;
237
+ }