@payez/next-mvp 4.4.5 → 4.4.7

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 (219) hide show
  1. package/README.md +10 -3
  2. package/dist/api/auth-handler.js +5 -3
  3. package/dist/api-handlers/account/change-password.js +33 -8
  4. package/dist/api-handlers/account/masked-info.js +2 -1
  5. package/dist/api-handlers/account/recovery/forward.d.ts +14 -0
  6. package/dist/api-handlers/account/recovery/forward.js +105 -0
  7. package/dist/api-handlers/account/recovery/initiate.js +4 -0
  8. package/dist/api-handlers/account/recovery/send-code.d.ts +12 -2
  9. package/dist/api-handlers/account/recovery/send-code.js +11 -84
  10. package/dist/api-handlers/account/recovery/verify-code.d.ts +11 -2
  11. package/dist/api-handlers/account/recovery/verify-code.js +10 -84
  12. package/dist/api-handlers/account/reset-password.js +24 -1
  13. package/dist/api-handlers/account/send-code.d.ts +1 -15
  14. package/dist/api-handlers/account/send-code.js +3 -6
  15. package/dist/api-handlers/account/update-phone.js +6 -1
  16. package/dist/api-handlers/account/validate-password.js +3 -1
  17. package/dist/api-handlers/account/verify-email.d.ts +1 -17
  18. package/dist/api-handlers/account/verify-email.js +4 -6
  19. package/dist/api-handlers/account/verify-sms.d.ts +1 -17
  20. package/dist/api-handlers/account/verify-sms.js +4 -6
  21. package/dist/api-handlers/admin/analytics.js +12 -4
  22. package/dist/api-handlers/admin/audit.js +12 -4
  23. package/dist/api-handlers/admin/redis-sessions.js +16 -8
  24. package/dist/api-handlers/admin/sessions.js +14 -6
  25. package/dist/api-handlers/admin/site-logs.js +39 -16
  26. package/dist/api-handlers/admin/stats.js +14 -4
  27. package/dist/api-handlers/admin/users.js +14 -6
  28. package/dist/api-handlers/admin/vibe-data.js +19 -11
  29. package/dist/api-handlers/auth/jwks.js +2 -1
  30. package/dist/api-handlers/auth/login.js +13 -4
  31. package/dist/api-handlers/auth/passkey-signin.js +6 -0
  32. package/dist/api-handlers/auth/refresh.js +38 -11
  33. package/dist/api-handlers/auth/signout.js +2 -1
  34. package/dist/api-handlers/auth/status.js +4 -1
  35. package/dist/api-handlers/auth/update-session.d.ts +25 -4
  36. package/dist/api-handlers/auth/update-session.js +38 -11
  37. package/dist/api-handlers/auth/validate.js +4 -2
  38. package/dist/api-handlers/auth/verify-code.js +3 -2
  39. package/dist/api-handlers/mfa/backup-code-verify.d.ts +1 -18
  40. package/dist/api-handlers/mfa/backup-code-verify.js +4 -6
  41. package/dist/api-handlers/mfa/backup-codes.js +2 -1
  42. package/dist/api-handlers/mfa/methods.js +2 -1
  43. package/dist/api-handlers/mfa/totp-confirm.js +2 -1
  44. package/dist/api-handlers/mfa/totp-enroll.js +2 -1
  45. package/dist/api-handlers/mfa/totp-verify.d.ts +1 -19
  46. package/dist/api-handlers/mfa/totp-verify.js +4 -6
  47. package/dist/api-handlers/passkeys/list.js +2 -1
  48. package/dist/api-handlers/passkeys/manage.js +2 -1
  49. package/dist/api-handlers/passkeys/register-options.js +2 -1
  50. package/dist/api-handlers/passkeys/register-verify.js +2 -1
  51. package/dist/api-handlers/session/refresh-viability.d.ts +4 -2
  52. package/dist/api-handlers/session/refresh-viability.js +10 -7
  53. package/dist/api-handlers/session/viability.js +4 -3
  54. package/dist/api-handlers/test/force-expire.js +5 -3
  55. package/dist/auth/auth-decision.js +2 -1
  56. package/dist/auth/better-auth.d.ts +58 -14
  57. package/dist/auth/better-auth.js +125 -54
  58. package/dist/auth/utils/idp-client.js +2 -1
  59. package/dist/client/better-auth-client.d.ts +101 -956
  60. package/dist/components/admin/DataBrowserTab.js +4 -1
  61. package/dist/components/admin/SessionsTab.js +9 -3
  62. package/dist/components/recovery/RequestedStep.d.ts +11 -0
  63. package/dist/components/recovery/RequestedStep.js +14 -0
  64. package/dist/components/recovery/SetPasswordStep.js +10 -1
  65. package/dist/config/env.d.ts +0 -2
  66. package/dist/config/env.js +0 -2
  67. package/dist/index.d.ts +1 -0
  68. package/dist/index.js +8 -1
  69. package/dist/lib/app-slug.d.ts +21 -0
  70. package/dist/lib/app-slug.js +51 -0
  71. package/dist/lib/ensure-fresh-access-token.d.ts +26 -0
  72. package/dist/lib/ensure-fresh-access-token.js +105 -4
  73. package/dist/lib/idp-client-config.d.ts +20 -0
  74. package/dist/lib/idp-client-config.js +73 -45
  75. package/dist/lib/idp-fetch.js +1 -1
  76. package/dist/lib/never-in-response.d.ts +30 -0
  77. package/dist/lib/never-in-response.js +71 -0
  78. package/dist/lib/password-rules.d.ts +22 -0
  79. package/dist/lib/password-rules.js +43 -0
  80. package/dist/lib/safe-error-response.d.ts +67 -0
  81. package/dist/lib/safe-error-response.js +130 -0
  82. package/dist/lib/session-cookie-shape.d.ts +22 -19
  83. package/dist/lib/session-cookie-shape.js +14 -18
  84. package/dist/lib/session-store.d.ts +8 -1
  85. package/dist/lib/session-store.js +170 -24
  86. package/dist/lib/startup-init.d.ts +6 -0
  87. package/dist/lib/startup-init.js +30 -4
  88. package/dist/lib/token-lifecycle.js +2 -1
  89. package/dist/lib/token-log-id.d.ts +18 -0
  90. package/dist/lib/token-log-id.js +84 -0
  91. package/dist/lib/two-factor-verify-failure.d.ts +78 -0
  92. package/dist/lib/two-factor-verify-failure.js +220 -0
  93. package/dist/middleware/create-middleware.d.ts +4 -1
  94. package/dist/middleware/create-middleware.js +79 -8
  95. package/dist/pages/login/page.js +5 -0
  96. package/dist/pages/recovery/page.js +14 -4
  97. package/dist/pages/test-env/JwtInspectPage.js +7 -149
  98. package/dist/pages/test-env/RefreshTokenPage.js +4 -1
  99. package/dist/pages/test-env/redact-credentials.d.ts +6 -0
  100. package/dist/pages/test-env/redact-credentials.js +101 -0
  101. package/dist/pages/verify-code/page.js +6 -3
  102. package/dist/routes/auth/logout.d.ts +2 -1
  103. package/dist/routes/auth/logout.js +4 -2
  104. package/dist/routes/auth/session.d.ts +0 -3
  105. package/dist/routes/auth/session.js +16 -10
  106. package/dist/routes/auth/settings.js +4 -1
  107. package/dist/routes/auth/viability.d.ts +3 -2
  108. package/dist/routes/auth/viability.js +11 -7
  109. package/dist/server/auth.d.ts +36 -294
  110. package/dist/server/auth.js +32 -31
  111. package/dist/server/decode-session.js +15 -26
  112. package/dist/server/verified-session-token.d.ts +13 -0
  113. package/dist/server/verified-session-token.js +103 -0
  114. package/dist/stores/authStore.js +14 -3
  115. package/dist/types/recovery.d.ts +1 -1
  116. package/dist/utils/api.d.ts +18 -0
  117. package/dist/utils/api.js +51 -9
  118. package/dist/vibe/client.d.ts +132 -16
  119. package/dist/vibe/client.js +288 -82
  120. package/dist/vibe/document-unwrap.d.ts +50 -0
  121. package/dist/vibe/document-unwrap.js +78 -0
  122. package/dist/vibe/errors.d.ts +17 -0
  123. package/dist/vibe/errors.js +21 -1
  124. package/dist/vibe/generic.d.ts +2 -49
  125. package/dist/vibe/generic.js +17 -78
  126. package/dist/vibe/index.d.ts +1 -1
  127. package/dist/vibe/index.js +2 -1
  128. package/dist/vibe/sessions.js +2 -1
  129. package/package.json +13 -2
  130. package/scripts/verify-release-provenance.mjs +410 -0
  131. package/src/api/auth-handler.ts +5 -3
  132. package/src/api-handlers/account/change-password.ts +36 -8
  133. package/src/api-handlers/account/masked-info.ts +2 -1
  134. package/src/api-handlers/account/recovery/forward.ts +117 -0
  135. package/src/api-handlers/account/recovery/initiate.ts +3 -0
  136. package/src/api-handlers/account/recovery/send-code.ts +13 -99
  137. package/src/api-handlers/account/recovery/verify-code.ts +12 -99
  138. package/src/api-handlers/account/reset-password.ts +30 -1
  139. package/src/api-handlers/account/send-code.ts +3 -9
  140. package/src/api-handlers/account/update-phone.ts +6 -1
  141. package/src/api-handlers/account/validate-password.ts +3 -1
  142. package/src/api-handlers/account/verify-email.ts +4 -9
  143. package/src/api-handlers/account/verify-sms.ts +4 -9
  144. package/src/api-handlers/admin/analytics.ts +13 -5
  145. package/src/api-handlers/admin/audit.ts +13 -5
  146. package/src/api-handlers/admin/redis-sessions.ts +16 -8
  147. package/src/api-handlers/admin/sessions.ts +15 -7
  148. package/src/api-handlers/admin/site-logs.ts +39 -16
  149. package/src/api-handlers/admin/stats.ts +15 -5
  150. package/src/api-handlers/admin/users.ts +15 -7
  151. package/src/api-handlers/admin/vibe-data.ts +20 -12
  152. package/src/api-handlers/auth/jwks.ts +2 -1
  153. package/src/api-handlers/auth/login.ts +13 -4
  154. package/src/api-handlers/auth/passkey-signin.ts +4 -0
  155. package/src/api-handlers/auth/refresh.ts +38 -11
  156. package/src/api-handlers/auth/signout.ts +2 -1
  157. package/src/api-handlers/auth/status.ts +4 -1
  158. package/src/api-handlers/auth/update-session.ts +45 -11
  159. package/src/api-handlers/auth/validate.ts +4 -2
  160. package/src/api-handlers/auth/verify-code.ts +3 -2
  161. package/src/api-handlers/mfa/backup-code-verify.ts +4 -9
  162. package/src/api-handlers/mfa/backup-codes.ts +2 -1
  163. package/src/api-handlers/mfa/methods.ts +2 -1
  164. package/src/api-handlers/mfa/totp-confirm.ts +2 -1
  165. package/src/api-handlers/mfa/totp-enroll.ts +2 -1
  166. package/src/api-handlers/mfa/totp-verify.ts +4 -9
  167. package/src/api-handlers/passkeys/list.ts +2 -1
  168. package/src/api-handlers/passkeys/manage.ts +2 -1
  169. package/src/api-handlers/passkeys/register-options.ts +2 -1
  170. package/src/api-handlers/passkeys/register-verify.ts +2 -1
  171. package/src/api-handlers/session/refresh-viability.ts +10 -7
  172. package/src/api-handlers/session/viability.ts +4 -3
  173. package/src/api-handlers/test/force-expire.ts +5 -3
  174. package/src/auth/auth-decision.ts +2 -1
  175. package/src/auth/better-auth.ts +128 -61
  176. package/src/auth/utils/idp-client.ts +2 -1
  177. package/src/components/admin/DataBrowserTab.tsx +4 -1
  178. package/src/components/admin/SessionsTab.tsx +10 -3
  179. package/src/components/recovery/RequestedStep.tsx +30 -0
  180. package/src/components/recovery/SetPasswordStep.tsx +24 -3
  181. package/src/config/env.ts +0 -2
  182. package/src/hooks/useViabilitySession.ts +2 -1
  183. package/src/index.ts +4 -0
  184. package/src/lib/app-slug.ts +50 -0
  185. package/src/lib/ensure-fresh-access-token.ts +133 -4
  186. package/src/lib/idp-client-config.ts +98 -45
  187. package/src/lib/idp-fetch.ts +1 -1
  188. package/src/lib/never-in-response.ts +64 -0
  189. package/src/lib/password-rules.ts +50 -0
  190. package/src/lib/safe-error-response.ts +126 -0
  191. package/src/lib/session-cookie-shape.ts +23 -22
  192. package/src/lib/session-store.ts +167 -24
  193. package/src/lib/startup-init.ts +29 -4
  194. package/src/lib/token-lifecycle.ts +2 -1
  195. package/src/lib/token-log-id.ts +69 -0
  196. package/src/lib/two-factor-verify-failure.ts +248 -0
  197. package/src/middleware/create-middleware.ts +97 -9
  198. package/src/pages/login/page.tsx +4 -0
  199. package/src/pages/recovery/page.tsx +21 -4
  200. package/src/pages/test-env/JwtInspectPage.tsx +11 -233
  201. package/src/pages/test-env/RefreshTokenPage.tsx +9 -4
  202. package/src/pages/test-env/redact-credentials.ts +96 -0
  203. package/src/pages/verify-code/page.tsx +6 -3
  204. package/src/routes/auth/logout.ts +4 -2
  205. package/src/routes/auth/session.ts +16 -10
  206. package/src/routes/auth/settings.ts +5 -1
  207. package/src/routes/auth/viability.ts +11 -7
  208. package/src/server/auth.ts +33 -35
  209. package/src/server/decode-session.ts +16 -26
  210. package/src/server/verified-session-token.ts +103 -0
  211. package/src/stores/authStore.ts +16 -5
  212. package/src/types/recovery.ts +1 -1
  213. package/src/utils/api.ts +47 -8
  214. package/src/vibe/client.ts +378 -91
  215. package/src/vibe/document-unwrap.ts +103 -0
  216. package/src/vibe/errors.ts +24 -0
  217. package/src/vibe/generic.ts +8 -100
  218. package/src/vibe/index.ts +1 -0
  219. package/src/vibe/sessions.ts +2 -1
@@ -28,22 +28,4 @@
28
28
  * @package @payez/next-mvp
29
29
  */
30
30
  import { NextRequest, NextResponse } from 'next/server';
31
- export declare function POST(req: NextRequest): Promise<NextResponse<{
32
- success: boolean;
33
- error: string;
34
- code: string;
35
- }> | NextResponse<{
36
- success: boolean;
37
- error: any;
38
- code: any;
39
- meta: {
40
- attemptedRefresh: boolean;
41
- };
42
- }> | NextResponse<{
43
- message: any;
44
- requiresChallenge?: boolean | undefined;
45
- nextStep?: "mfa_verify" | undefined;
46
- success: boolean;
47
- verificationSuccessful: boolean;
48
- twoFactorSessionVerified: boolean;
49
- }>>;
31
+ export declare function POST(req: NextRequest): Promise<NextResponse<unknown>>;
@@ -36,6 +36,7 @@ const env_1 = require("../../config/env");
36
36
  const test_aware_get_token_1 = require("../../lib/test-aware-get-token");
37
37
  const session_store_1 = require("../../lib/session-store");
38
38
  const jwt_decode_1 = require("../../lib/jwt-decode");
39
+ const two_factor_verify_failure_1 = require("../../lib/two-factor-verify-failure");
39
40
  async function POST(req) {
40
41
  try {
41
42
  const body = await req.json();
@@ -55,12 +56,9 @@ async function POST(req) {
55
56
  body: JSON.stringify({ code }),
56
57
  });
57
58
  if (!result.ok) {
58
- return server_1.NextResponse.json({
59
- success: false,
60
- error: result.json?.message || 'Verification failed',
61
- code: result.json?.code || 'IDP_ERROR',
62
- meta: { attemptedRefresh: result.attemptedRefresh },
63
- }, { status: result.status });
59
+ // PAY-1443: never relay the IDP's error text - it arrives as a C# anonymous-object
60
+ // ToString ("{ message = ... }") on the deployed IDP. Classify it, answer a fixed sentence.
61
+ return (0, two_factor_verify_failure_1.twoFactorVerifyFailure)(result, 'totp');
64
62
  }
65
63
  // Unwrap IDP envelope { success, data }
66
64
  const unwrappedData = result.json?.data || result.json;
@@ -4,6 +4,7 @@ exports.GET = GET;
4
4
  const server_1 = require("next/server");
5
5
  const idp_fetch_1 = require("../../lib/idp-fetch");
6
6
  const env_1 = require("../../config/env");
7
+ const safe_error_response_1 = require("../../lib/safe-error-response");
7
8
  /**
8
9
  * List the signed-in user's passkeys (GET /api/Passkeys, user JWT).
9
10
  * Probe-verified live 2026-08-01 (anon -> 401 = routed).
@@ -15,7 +16,7 @@ async function GET(req) {
15
16
  return server_1.NextResponse.json({
16
17
  success: false,
17
18
  message: 'Upstream error',
18
- error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: result.json },
19
+ error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: (0, safe_error_response_1.projectIdpError)(result.json) },
19
20
  meta: { attemptedRefresh: result.attemptedRefresh },
20
21
  }, { status: result.status });
21
22
  }
@@ -5,6 +5,7 @@ exports.DELETE = DELETE;
5
5
  const server_1 = require("next/server");
6
6
  const idp_fetch_1 = require("../../lib/idp-fetch");
7
7
  const env_1 = require("../../config/env");
8
+ const safe_error_response_1 = require("../../lib/safe-error-response");
8
9
  /**
9
10
  * Manage ONE passkey (PATCH rename / DELETE revoke, /api/Passkeys/{id},
10
11
  * user JWT). The id arrives from the Next dynamic segment via the routes
@@ -14,7 +15,7 @@ function upstreamError(result) {
14
15
  return server_1.NextResponse.json({
15
16
  success: false,
16
17
  message: 'Upstream error',
17
- error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: result.json },
18
+ error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: (0, safe_error_response_1.projectIdpError)(result.json) },
18
19
  meta: { attemptedRefresh: result.attemptedRefresh },
19
20
  }, { status: result.status });
20
21
  }
@@ -4,6 +4,7 @@ exports.POST = POST;
4
4
  const server_1 = require("next/server");
5
5
  const idp_fetch_1 = require("../../lib/idp-fetch");
6
6
  const env_1 = require("../../config/env");
7
+ const safe_error_response_1 = require("../../lib/safe-error-response");
7
8
  /**
8
9
  * Begin the passkey REGISTRATION ceremony (POST /api/Passkeys/register/options,
9
10
  * user JWT — a credential change; the IDP may demand step-up, surfaced as-is).
@@ -27,7 +28,7 @@ async function POST(req) {
27
28
  return server_1.NextResponse.json({
28
29
  success: false,
29
30
  message: 'Upstream error',
30
- error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: result.json },
31
+ error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: (0, safe_error_response_1.projectIdpError)(result.json) },
31
32
  meta: { attemptedRefresh: result.attemptedRefresh },
32
33
  }, { status: result.status });
33
34
  }
@@ -4,6 +4,7 @@ exports.POST = POST;
4
4
  const server_1 = require("next/server");
5
5
  const idp_fetch_1 = require("../../lib/idp-fetch");
6
6
  const env_1 = require("../../config/env");
7
+ const safe_error_response_1 = require("../../lib/safe-error-response");
7
8
  /**
8
9
  * Finish the passkey REGISTRATION ceremony (POST /api/Passkeys/register/verify,
9
10
  * user JWT). Body forwarded VERBATIM — it carries the enrolment handle plus the
@@ -26,7 +27,7 @@ async function POST(req) {
26
27
  return server_1.NextResponse.json({
27
28
  success: false,
28
29
  message: 'Upstream error',
29
- error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: result.json },
30
+ error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: (0, safe_error_response_1.projectIdpError)(result.json) },
30
31
  meta: { attemptedRefresh: result.attemptedRefresh },
31
32
  }, { status: result.status });
32
33
  }
@@ -2,13 +2,15 @@ import { NextRequest, NextResponse } from 'next/server';
2
2
  export declare function GET(req: NextRequest): Promise<NextResponse<{
3
3
  canRefresh: boolean;
4
4
  reason: string;
5
- sessionToken: null;
5
+ sessionTokenId: null;
6
6
  }> | NextResponse<{
7
7
  canRefresh: boolean;
8
8
  reason: string;
9
- sessionToken: string;
9
+ sessionTokenId: string;
10
10
  }> | NextResponse<{
11
11
  canRefresh: boolean;
12
12
  reason: string;
13
13
  error: string;
14
+ code: string;
15
+ correlationId: string;
14
16
  }>>;
@@ -6,6 +6,7 @@ const session_store_1 = require("../../lib/session-store");
6
6
  const refresh_token_validator_1 = require("../../lib/refresh-token-validator");
7
7
  const test_aware_get_token_1 = require("../../lib/test-aware-get-token");
8
8
  const logger_1 = require("../../config/logger");
9
+ const token_log_id_1 = require("../../lib/token-log-id");
9
10
  async function GET(req) {
10
11
  try {
11
12
  const sessionToken = req.nextUrl.searchParams.get('token');
@@ -16,24 +17,26 @@ async function GET(req) {
16
17
  finalSessionToken = (token?.sessionToken || token?.redisSessionId);
17
18
  }
18
19
  if (!finalSessionToken) {
19
- return server_1.NextResponse.json({ canRefresh: false, reason: 'not_logged_in', sessionToken: null }, { status: 200 });
20
+ return server_1.NextResponse.json({ canRefresh: false, reason: 'not_logged_in', sessionTokenId: null }, { status: 200 });
20
21
  }
21
22
  const refreshInProgress = await (0, session_store_1.isRefreshInProgress)(finalSessionToken);
22
23
  if (refreshInProgress) {
23
24
  // Still need to get session data for twoFactorComplete even when refresh is in progress
24
25
  const sessionData = await (0, session_store_1.getSession)(finalSessionToken);
25
- logger_1.logger.info('[REFRESH-VIABILITY] Refresh already in progress, telling middleware to wait', { sessionToken: finalSessionToken.substring(0, 8) + '...' });
26
- return server_1.NextResponse.json({ canRefresh: true, reason: 'refresh_in_progress', refreshInProgress: true, sessionToken: finalSessionToken, twoFactorComplete: sessionData?.mfaVerified ?? false }, { status: 200 });
26
+ logger_1.logger.info('[REFRESH-VIABILITY] Refresh already in progress, telling middleware to wait', { sessionToken: (0, token_log_id_1.tokenLogId)(finalSessionToken) });
27
+ return server_1.NextResponse.json({ canRefresh: true, reason: 'refresh_in_progress', refreshInProgress: true, sessionTokenId: (0, token_log_id_1.tokenLogId)(finalSessionToken), twoFactorComplete: sessionData?.mfaVerified ?? false }, { status: 200 });
27
28
  }
28
29
  const sessionData = await (0, session_store_1.getSession)(finalSessionToken);
29
30
  if (!sessionData) {
30
- return server_1.NextResponse.json({ canRefresh: false, reason: 'session_not_found', sessionToken: finalSessionToken }, { status: 200 });
31
+ return server_1.NextResponse.json({ canRefresh: false, reason: 'session_not_found', sessionTokenId: (0, token_log_id_1.tokenLogId)(finalSessionToken) }, { status: 200 });
31
32
  }
32
33
  const viabilityCheck = (0, refresh_token_validator_1.checkRefreshViability)(sessionData);
33
- return server_1.NextResponse.json({ canRefresh: viabilityCheck.canRefresh, reason: viabilityCheck.reason, timeRemaining: viabilityCheck.timeRemaining, expiresAt: viabilityCheck.expiresAt, accessTokenExpired: viabilityCheck.accessTokenExpired, accessTokenTimeRemaining: viabilityCheck.accessTokenTimeRemaining, sessionToken: finalSessionToken, twoFactorComplete: sessionData.mfaVerified ?? false, userId: sessionData.userId, refreshInProgress: false });
34
+ return server_1.NextResponse.json({ canRefresh: viabilityCheck.canRefresh, reason: viabilityCheck.reason, timeRemaining: viabilityCheck.timeRemaining, expiresAt: viabilityCheck.expiresAt, accessTokenExpired: viabilityCheck.accessTokenExpired, accessTokenTimeRemaining: viabilityCheck.accessTokenTimeRemaining, sessionTokenId: (0, token_log_id_1.tokenLogId)(finalSessionToken), twoFactorComplete: sessionData.mfaVerified ?? false, userId: sessionData.userId, refreshInProgress: false });
34
35
  }
35
36
  catch (error) {
36
- logger_1.logger.error('[REFRESH-VIABILITY] Error checking refresh viability', { error: error instanceof Error ? error.message : String(error) });
37
- return server_1.NextResponse.json({ canRefresh: false, reason: 'check_error', error: error instanceof Error ? error.message : String(error) }, { status: 500 });
37
+ const correlationId = globalThis.crypto.randomUUID();
38
+ logger_1.logger.error('[REFRESH-VIABILITY] Error checking refresh viability', { correlationId, error: error instanceof Error ? error.message : String(error) });
39
+ // PAY-1438: the exception text stays in the log above; the caller gets the id.
40
+ return server_1.NextResponse.json({ canRefresh: false, reason: 'check_error', error: 'Failed to check refresh viability', code: 'INTERNAL_ERROR', correlationId }, { status: 500 });
38
41
  }
39
42
  }
@@ -11,6 +11,7 @@ const session_store_1 = require("../../lib/session-store");
11
11
  const auth_1 = require("../../server/auth");
12
12
  const startup_init_1 = require("../../lib/startup-init");
13
13
  const idp_client_config_1 = require("../../lib/idp-client-config");
14
+ const token_log_id_1 = require("../../lib/token-log-id");
14
15
  async function GET(req) {
15
16
  try {
16
17
  // Ensure initialization is complete (auth signing secret resolved from IDP)
@@ -109,7 +110,7 @@ async function GET(req) {
109
110
  const sessionMfaComplete = sessionData.mfaVerified ?? false;
110
111
  const effectiveTwoFactorComplete = sessionMfaComplete && !mfaExpired;
111
112
  console.log('[VIABILITY] Session 2FA check:', {
112
- sessionToken: sessionToken.substring(0, 8) + '...',
113
+ sessionToken: (0, token_log_id_1.tokenLogId)(sessionToken),
113
114
  mfaVerified: sessionData.mfaVerified,
114
115
  twoFactorComplete: sessionData.twoFactorComplete,
115
116
  sessionMfaComplete,
@@ -125,7 +126,7 @@ async function GET(req) {
125
126
  }
126
127
  const response = {
127
128
  authenticated: true,
128
- sessionToken, // Include token for middleware tracking
129
+ sessionTokenId: (0, token_log_id_1.tokenLogId)(sessionToken), // PAY-1481: correlation id for middleware tracking, never the token
129
130
  // 2FA fields - critical for middleware redirect logic
130
131
  requires2FA, // From cached client config (client-wide setting)
131
132
  twoFactorComplete: effectiveTwoFactorComplete, // From session, BUT respects MFA TTL
@@ -159,7 +160,7 @@ async function GET(req) {
159
160
  console.warn('[VIABILITY] Stale cookie detected - session not in Redis');
160
161
  return server_1.NextResponse.json({
161
162
  authenticated: false,
162
- sessionToken // Include token to enable stale cookie detection
163
+ sessionTokenId: sessionToken ? (0, token_log_id_1.tokenLogId)(sessionToken) : null // PAY-1481: presence + correlation for stale cookie detection
163
164
  });
164
165
  }
165
166
  // If there's no token at all, it's not authenticated
@@ -4,6 +4,8 @@ exports.POST = void 0;
4
4
  const server_1 = require("next/server");
5
5
  const auth_1 = require("../../server/auth");
6
6
  const session_store_1 = require("../../lib/session-store");
7
+ const safe_error_response_1 = require("../../lib/safe-error-response");
8
+ const token_log_id_1 = require("../../lib/token-log-id");
7
9
  /**
8
10
  * ⚠️ DESTRUCTIVE TEST-ONLY HANDLER — DO NOT MOUNT IN PRODUCTION. ⚠️
9
11
  *
@@ -134,7 +136,7 @@ const POST = async (req) => {
134
136
  const prev = session.idpAccessTokenExpires || null;
135
137
  await (0, session_store_1.updateSession)(sessionToken, { idpAccessTokenExpires: forced });
136
138
  console.log('[TEST_EXPIRE] Forced access token expiry for session', {
137
- sessionToken: sessionToken.substring(0, 8) + '...',
139
+ sessionToken: (0, token_log_id_1.tokenLogId)(sessionToken),
138
140
  previous: prev ? new Date(prev).toISOString() : null,
139
141
  newExpiry: new Date(forced).toISOString()
140
142
  });
@@ -147,8 +149,8 @@ const POST = async (req) => {
147
149
  });
148
150
  }
149
151
  catch (e) {
150
- console.error('[TEST_EXPIRE] Error:', e);
151
- return server_1.NextResponse.json({ success: false, error: e instanceof Error ? e.message : String(e) }, { status: 500 });
152
+ const correlationId = (0, safe_error_response_1.logExceptionWithCorrelation)('[TEST_EXPIRE] Error:', e);
153
+ return server_1.NextResponse.json({ success: false, error: 'Failed to force expiry', code: 'INTERNAL_ERROR', correlationId }, { status: 500 });
152
154
  }
153
155
  };
154
156
  exports.POST = POST;
@@ -8,6 +8,7 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.makeAuthDecision = makeAuthDecision;
10
10
  const safe_callback_1 = require("./safe-callback");
11
+ const token_log_id_1 = require("../lib/token-log-id");
11
12
  /**
12
13
  * Main decision function - pure, testable, deterministic
13
14
  */
@@ -99,7 +100,7 @@ function makeAuthDecision(context) {
99
100
  pathname,
100
101
  isLoginPage,
101
102
  sessionExists: sessionStatus.exists,
102
- sessionToken: sessionPointer.sessionToken?.substring(0, 8) + '...'
103
+ sessionToken: (0, token_log_id_1.tokenLogId)(sessionPointer.sessionToken)
103
104
  });
104
105
  // Already on the 2FA page
105
106
  if (pathname === '/account-auth/verify-code') {
@@ -182,6 +182,9 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig, opt
182
182
  refreshCache: false;
183
183
  };
184
184
  };
185
+ account: {
186
+ storeStateStrategy: "cookie";
187
+ };
185
188
  advanced: {
186
189
  cookiePrefix: string;
187
190
  cookies: {
@@ -192,22 +195,25 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig, opt
192
195
  };
193
196
  plugins: [{
194
197
  id: "next-cookies";
198
+ version: string;
195
199
  hooks: {
196
200
  before: {
197
201
  matcher(ctx: import("better-auth").HookEndpointContext): boolean;
198
- handler: (inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<void>;
202
+ handler: import("better-auth").Middleware<import("better-auth").MiddlewareOptions, (inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<void>>;
199
203
  }[];
200
204
  after: {
201
205
  matcher(ctx: import("better-auth").HookEndpointContext): true;
202
- handler: (inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<void>;
206
+ handler: import("better-auth").Middleware<import("better-auth").MiddlewareOptions, (inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<void>>;
203
207
  }[];
204
208
  };
205
- }, ...(import("better-auth").BetterAuthPlugin | {
209
+ }, ...({
206
210
  id: "magic-link";
211
+ version: string;
207
212
  endpoints: {
208
213
  signInMagicLink: import("better-auth").StrictEndpoint<"/sign-in/magic-link", {
209
214
  method: "POST";
210
215
  requireHeaders: true;
216
+ use: import("better-auth").Middleware<import("better-auth").MiddlewareOptions, (inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<void>>[];
211
217
  body: import("better-auth").ZodObject<{
212
218
  email: import("better-auth").ZodEmail;
213
219
  name: import("better-auth").ZodOptional<import("better-auth").ZodString>;
@@ -215,7 +221,7 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig, opt
215
221
  newUserCallbackURL: import("better-auth").ZodOptional<import("better-auth").ZodString>;
216
222
  errorCallbackURL: import("better-auth").ZodOptional<import("better-auth").ZodString>;
217
223
  metadata: import("better-auth").ZodOptional<import("better-auth").ZodRecord<import("better-auth").ZodString, import("better-auth").ZodAny>>;
218
- }, import("better-auth").$strip>;
224
+ }, import("zod/v4/core").$strip>;
219
225
  metadata: {
220
226
  openapi: {
221
227
  operationId: string;
@@ -249,8 +255,8 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig, opt
249
255
  callbackURL: import("better-auth").ZodOptional<import("better-auth").ZodString>;
250
256
  errorCallbackURL: import("better-auth").ZodOptional<import("better-auth").ZodString>;
251
257
  newUserCallbackURL: import("better-auth").ZodOptional<import("better-auth").ZodString>;
252
- }, import("better-auth").$strip>;
253
- use: ((inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<void>)[];
258
+ }, import("zod/v4/core").$strip>;
259
+ use: import("better-auth").Middleware<import("better-auth").MiddlewareOptions, (inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<void>>[];
254
260
  requireHeaders: true;
255
261
  metadata: {
256
262
  openapi: {
@@ -289,6 +295,16 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig, opt
289
295
  name: string;
290
296
  image?: string | null | undefined;
291
297
  };
298
+ session: {
299
+ id: string;
300
+ createdAt: Date;
301
+ updatedAt: Date;
302
+ userId: string;
303
+ expiresAt: Date;
304
+ token: string;
305
+ ipAddress?: string | null | undefined;
306
+ userAgent?: string | null | undefined;
307
+ };
292
308
  }>;
293
309
  };
294
310
  rateLimit: {
@@ -297,8 +313,9 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig, opt
297
313
  max: number;
298
314
  }[];
299
315
  options: MagicLinkOptions;
300
- } | {
316
+ } | import("better-auth").BetterAuthPlugin | {
301
317
  id: "generic-oauth";
318
+ version: string;
302
319
  init: (ctx: import("better-auth").AuthContext) => {
303
320
  context: {
304
321
  socialProviders: import("better-auth").OAuthProvider<Record<string, any>, Partial<import("better-auth").ProviderOptions<any>>>[];
@@ -316,7 +333,7 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig, opt
316
333
  scopes: import("better-auth").ZodOptional<import("better-auth").ZodArray<import("better-auth").ZodString>>;
317
334
  requestSignUp: import("better-auth").ZodOptional<import("better-auth").ZodBoolean>;
318
335
  additionalData: import("better-auth").ZodOptional<import("better-auth").ZodRecord<import("better-auth").ZodString, import("better-auth").ZodAny>>;
319
- }, import("better-auth").$strip>;
336
+ }, import("zod/v4/core").$strip>;
320
337
  metadata: {
321
338
  openapi: {
322
339
  description: string;
@@ -354,7 +371,7 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig, opt
354
371
  error_description: import("better-auth").ZodOptional<import("better-auth").ZodString>;
355
372
  state: import("better-auth").ZodOptional<import("better-auth").ZodString>;
356
373
  iss: import("better-auth").ZodOptional<import("better-auth").ZodString>;
357
- }, import("better-auth").$strip>;
374
+ }, import("zod/v4/core").$strip>;
358
375
  metadata: {
359
376
  allowedMediaTypes: string[];
360
377
  openapi: {
@@ -379,7 +396,7 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig, opt
379
396
  };
380
397
  scope: "server";
381
398
  };
382
- }, void>;
399
+ }, never>;
383
400
  oAuth2LinkAccount: import("better-auth").StrictEndpoint<"/oauth2/link", {
384
401
  method: "POST";
385
402
  body: import("better-auth").ZodObject<{
@@ -387,8 +404,8 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig, opt
387
404
  callbackURL: import("better-auth").ZodString;
388
405
  scopes: import("better-auth").ZodOptional<import("better-auth").ZodArray<import("better-auth").ZodString>>;
389
406
  errorCallbackURL: import("better-auth").ZodOptional<import("better-auth").ZodString>;
390
- }, import("better-auth").$strip>;
391
- use: ((inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<{
407
+ }, import("zod/v4/core").$strip>;
408
+ use: import("better-auth").Middleware<import("better-auth").MiddlewareOptions, (inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<{
392
409
  session: {
393
410
  session: Record<string, any> & {
394
411
  id: string;
@@ -410,7 +427,7 @@ export declare function createBetterAuthInstance(idpConfig: IDPClientConfig, opt
410
427
  image?: string | null | undefined;
411
428
  };
412
429
  };
413
- }>)[];
430
+ }>>[];
414
431
  metadata: {
415
432
  openapi: {
416
433
  description: string;
@@ -476,6 +493,20 @@ export declare function __getBetterAuthInstance(): unknown;
476
493
  * cannot be applied retroactively.
477
494
  */
478
495
  export declare function configureBetterAuth(opts: CreateBetterAuthInstanceOptions): void;
496
+ /**
497
+ * PAY-642 (card 338215): the init attempt no longer LATCHES A FAILURE.
498
+ *
499
+ * This used to be `state.initPromise ??= getIDPClientConfig(true).then(...)` with no .catch and no reset. One
500
+ * auth request against a cold process while the IdP was unreachable stored a rejected promise, and every later
501
+ * caller replayed it until the process restarted, even after the IdP recovered. This funnel backs every
502
+ * /api/auth/* route, the login GET handler and withAuth. server/auth.ts getAuthInstance() already used
503
+ * createSingleFlight for this exact bug; this sibling funnel was missed.
504
+ *
505
+ * Now the attempt runs through the same helper: concurrent callers share one attempt, a failure still rejects
506
+ * for every caller of THAT attempt (loud), the next call starts a fresh attempt, and a success is cached in
507
+ * state.cachedInstance as before. The flight lives on the globalThis state for the same reason the instance
508
+ * does (duplicated route chunks must share one init).
509
+ */
479
510
  export declare function getBetterAuthInstance(): Promise<any>;
480
511
  /**
481
512
  * Get flag-gated auth handler for Next.js route.
@@ -551,12 +582,25 @@ export declare function exchangeOAuthForIdpTokens(sessionToken: string, provider
551
582
  * state what actually authenticated ('passkey', 'google').
552
583
  */
553
584
  export declare function storeIdpTokensInSession(sessionToken: string, idpTokenData: Record<string, unknown>, authProvider: string): Promise<boolean>;
585
+ /**
586
+ * The `?error=` code the login page receives when an OAuth sign-in is ABORTED because the IdP exchange did not
587
+ * store tokens (PAY-1733). Hosts map it to ONE neutral line; the card's words are "That sign-in didn't work.
588
+ * Try again or use another method." The cause stays in the server log, never on the page.
589
+ */
590
+ export declare const OAUTH_SIGN_IN_FAILED_ERROR = "OAUTH_SIGN_IN_FAILED";
591
+ /**
592
+ * Re-emit each cookie the callback response SET as an immediate expiry, keeping the attributes that decide
593
+ * WHICH cookie the browser overwrites (Path, Domain, Secure, SameSite, HttpOnly - a `__Secure-` name is only
594
+ * accepted with Secure) and dropping Expires/Max-Age in favour of Max-Age=0.
595
+ */
596
+ export declare function expireSetCookies(setCookies: readonly string[]): string[];
554
597
  /**
555
598
  * Create a production-ready GET handler for the auth catch-all route.
556
599
  *
557
600
  * Wraps better-auth's GET handler with:
558
601
  * - OAuth state error recovery (redirects to login instead of error page)
559
- * - IDP token exchange after successful OAuth callback
602
+ * - IDP token exchange after successful OAuth callback - and, when it stores no tokens, the sign-in is ABORTED
603
+ * (session destroyed, cookies expired, login page with OAUTH_SIGN_IN_FAILED; PAY-1733)
560
604
  *
561
605
  * Usage in host app:
562
606
  * ```ts