@payez/next-mvp 4.8.1 → 4.8.3
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.
- package/POST-INSTALL.md +408 -408
- package/README.md +859 -859
- package/dist/api-handlers/admin/audit.js +13 -21
- package/dist/api-handlers/admin/sessions.js +59 -45
- package/dist/api-handlers/admin/stats.js +1 -1
- package/dist/api-handlers/admin/users.js +15 -23
- package/dist/api-handlers/admin/vibe-data.d.ts +5 -0
- package/dist/api-handlers/admin/vibe-data.js +5 -0
- package/dist/components/account/MobileNavDrawer.js +18 -18
- package/dist/components/account/UserAvatarMenu.js +1 -1
- package/dist/components/admin/AlertSettingsTab.js +40 -40
- package/dist/components/admin/LoggingSettingsTab.js +28 -28
- package/dist/lib/session-store.js +21 -21
- package/dist/lib/startup-init.js +19 -19
- package/dist/pages/login/page.js +28 -28
- package/dist/pages/settings/EnhancedSettingsPage.js +17 -17
- package/dist/vibe/client.d.ts +1 -1
- package/dist/vibe/client.js +2 -1
- package/dist/vibe/filters.d.ts +36 -0
- package/dist/vibe/filters.js +47 -0
- package/dist/vibe/generic.js +2 -1
- package/dist/vibe/sessions.js +28 -3
- package/package.json +2 -2
- package/scripts/check-publish-eol.mjs +33 -15
- package/src/api/auth-handler.ts +550 -550
- package/src/api/index.ts +17 -17
- package/src/api-handlers/account/change-password.ts +170 -170
- package/src/api-handlers/account/masked-info.ts +46 -46
- package/src/api-handlers/account/profile.ts +99 -99
- package/src/api-handlers/account/recovery/forward.ts +117 -117
- package/src/api-handlers/account/recovery/initiate.ts +59 -59
- package/src/api-handlers/account/recovery/send-code.ts +21 -21
- package/src/api-handlers/account/recovery/verify-code.ts +20 -20
- package/src/api-handlers/account/reset-password.ts +87 -87
- package/src/api-handlers/account/send-code.ts +70 -70
- package/src/api-handlers/account/update-phone.ts +84 -84
- package/src/api-handlers/account/validate-password.ts +139 -139
- package/src/api-handlers/account/verify-email.ts +134 -134
- package/src/api-handlers/account/verify-sms.ts +134 -134
- package/src/api-handlers/admin/analytics.ts +452 -452
- package/src/api-handlers/admin/audit.ts +223 -232
- package/src/api-handlers/admin/index.ts +63 -63
- package/src/api-handlers/admin/redis-sessions.ts +259 -259
- package/src/api-handlers/admin/sessions.ts +341 -327
- package/src/api-handlers/admin/site-logs.ts +388 -388
- package/src/api-handlers/admin/stats.ts +260 -260
- package/src/api-handlers/admin/users.ts +240 -251
- package/src/api-handlers/admin/vibe-data.ts +338 -333
- package/src/api-handlers/anon/preferences.ts +123 -123
- package/src/api-handlers/auth/credential-login-email-code.ts +92 -92
- package/src/api-handlers/auth/credential-login.ts +948 -948
- package/src/api-handlers/auth/jwks.ts +31 -31
- package/src/api-handlers/auth/login.ts +252 -252
- package/src/api-handlers/auth/passkey-signin.ts +116 -116
- package/src/api-handlers/auth/refresh.ts +829 -829
- package/src/api-handlers/auth/signout.ts +201 -201
- package/src/api-handlers/auth/status.ts +23 -23
- package/src/api-handlers/auth/update-session.ts +144 -144
- package/src/api-handlers/auth/validate.ts +45 -45
- package/src/api-handlers/auth/verify-code.ts +116 -116
- package/src/api-handlers/mfa/backup-code-verify.ts +170 -170
- package/src/api-handlers/mfa/backup-codes.ts +42 -42
- package/src/api-handlers/mfa/methods.ts +47 -47
- package/src/api-handlers/mfa/totp-confirm.ts +43 -43
- package/src/api-handlers/mfa/totp-enroll.ts +43 -43
- package/src/api-handlers/mfa/totp-verify.ts +172 -172
- package/src/api-handlers/oauth/resume.ts +182 -182
- package/src/api-handlers/onboarding/send-email-code.ts +18 -18
- package/src/api-handlers/onboarding/set-password.ts +21 -21
- package/src/api-handlers/onboarding/verify-code.ts +20 -20
- package/src/api-handlers/onboarding/verify-welcome-email.ts +17 -17
- package/src/api-handlers/passkeys/list.ts +32 -32
- package/src/api-handlers/passkeys/manage.ts +55 -55
- package/src/api-handlers/passkeys/register-options.ts +43 -43
- package/src/api-handlers/passkeys/register-verify.ts +42 -42
- package/src/api-handlers/session/refresh-viability.ts +56 -56
- package/src/api-handlers/session/viability.ts +238 -238
- package/src/api-handlers/test/force-expire.ts +167 -167
- package/src/auth/auth-decision.ts +292 -292
- package/src/auth/better-auth.ts +1688 -1688
- package/src/auth/idp-oauth.ts +310 -310
- package/src/auth/password-reset-bridge.ts +98 -98
- package/src/auth/revocation-fields.ts +16 -16
- package/src/auth/route-config.ts +236 -236
- package/src/auth/safe-callback.ts +199 -199
- package/src/auth/session-cookie-clear.ts +30 -30
- package/src/auth/session-reset-link.ts +159 -159
- package/src/auth/session-response-sanitizer.ts +151 -151
- package/src/auth/types/auth-types.ts +555 -555
- package/src/auth/types/index.ts +7 -7
- package/src/auth/unauthenticated-routes.ts +2 -2
- package/src/auth/utils/idp-client.ts +364 -364
- package/src/auth/utils/index.ts +6 -6
- package/src/auth/utils/token-utils.ts +243 -243
- package/src/client/AuthContext.tsx +192 -192
- package/src/client/better-auth-client.ts +70 -70
- package/src/client/fetch-with-auth.ts +47 -47
- package/src/client/fetchWithSession.ts +21 -21
- package/src/client/index.ts +13 -13
- package/src/client/useAnonSession.ts +131 -131
- package/src/components/SessionSync.tsx +138 -138
- package/src/components/SignalRHealthCheck.tsx +131 -131
- package/src/components/account/MobileNavDrawer.tsx +305 -305
- package/src/components/account/UserAvatarMenu.tsx +277 -277
- package/src/components/account/index.ts +13 -13
- package/src/components/admin/AlertSettingsTab.tsx +728 -728
- package/src/components/admin/AnalyticsTab.tsx +703 -703
- package/src/components/admin/DataBrowserTab.tsx +508 -508
- package/src/components/admin/LoggingSettingsTab.tsx +665 -665
- package/src/components/admin/SessionsTab.tsx +421 -421
- package/src/components/admin/StatsTab.tsx +379 -379
- package/src/components/admin/VibeAdminContext.tsx +87 -87
- package/src/components/admin/VibeAdminLayout.tsx +187 -187
- package/src/components/admin/index.ts +59 -59
- package/src/components/auth/CredentialSignInForm.tsx +240 -240
- package/src/components/auth/FederatedAuthSection.tsx +129 -129
- package/src/components/auth/ModeAwareLoginPage.tsx +146 -146
- package/src/components/auth/ModeAwareSignupPage.tsx +200 -200
- package/src/components/auth/PasswordResetBridge.tsx +30 -30
- package/src/components/auth/TraditionalAuthSection.tsx +103 -103
- package/src/components/recovery/CompleteStep.tsx +36 -36
- package/src/components/recovery/InitiateRecoveryStep.tsx +68 -68
- package/src/components/recovery/RequestedStep.tsx +30 -30
- package/src/components/recovery/SelectMethodStep.tsx +73 -73
- package/src/components/recovery/SetPasswordStep.tsx +118 -118
- package/src/components/recovery/VerifyCodeStep.tsx +90 -90
- package/src/components/reserved/ReservedRecoveryWarning.tsx +160 -160
- package/src/components/reserved/ReservedStatusBox.tsx +118 -118
- package/src/components/ui/BetaBadge.tsx +58 -58
- package/src/components/ui/Footer.tsx +93 -93
- package/src/config/env.ts +55 -55
- package/src/config/logger.ts +62 -62
- package/src/config/logging-config.ts +82 -82
- package/src/config/unauthenticated-routes.ts +19 -19
- package/src/config/vibe-log-transport.ts +264 -264
- package/src/edge/internal-api-url.ts +65 -65
- package/src/edge/middleware.ts +42 -42
- package/src/hooks/useAuth.ts +117 -117
- package/src/hooks/useAuthSettings.ts +109 -109
- package/src/hooks/useAvailableProviders.ts +143 -143
- package/src/hooks/usePasswordValidation.ts +127 -127
- package/src/hooks/useProfile.ts +82 -82
- package/src/hooks/usePublicAuthSettings.ts +171 -171
- package/src/hooks/useSessionExpiration.ts +101 -101
- package/src/hooks/useViabilitySession.ts +337 -337
- package/src/index.ts +64 -64
- package/src/lib/anon-session.ts +213 -213
- package/src/lib/api-handler.ts +643 -643
- package/src/lib/app-slug.ts +228 -228
- package/src/lib/authorize-resume.ts +172 -172
- package/src/lib/bearer-fetch.ts +31 -31
- package/src/lib/client-key.ts +88 -88
- package/src/lib/code-step-copy.ts +83 -83
- package/src/lib/credential-sign-in-client.ts +101 -101
- package/src/lib/demo-mode.ts +18 -18
- package/src/lib/device-id.ts +67 -67
- package/src/lib/ensure-fresh-access-token.ts +509 -509
- package/src/lib/geolocation.ts +265 -265
- package/src/lib/idp-client-config.ts +1005 -1005
- package/src/lib/idp-fetch.ts +169 -169
- package/src/lib/idp-url-guard.ts +37 -37
- package/src/lib/internal-api.ts +171 -171
- package/src/lib/jwt-decode-client.ts +45 -45
- package/src/lib/jwt-decode.ts +82 -82
- package/src/lib/lock-window.ts +49 -49
- package/src/lib/login-error-message.ts +41 -41
- package/src/lib/never-in-response.ts +64 -64
- package/src/lib/nextauth-secret.ts +168 -168
- package/src/lib/onboarding-proxy.ts +57 -57
- package/src/lib/password-rules.ts +50 -50
- package/src/lib/rate-limit-service.ts +9 -9
- package/src/lib/redis.ts +105 -105
- package/src/lib/refresh-token-validator.ts +64 -64
- package/src/lib/roles.ts +177 -177
- package/src/lib/safe-error-response.ts +149 -149
- package/src/lib/secret-validation.ts +8 -8
- package/src/lib/session-cookie-shape.ts +185 -185
- package/src/lib/session-store.ts +1092 -1092
- package/src/lib/session.ts +34 -34
- package/src/lib/single-flight.ts +64 -64
- package/src/lib/site-logger.ts +245 -245
- package/src/lib/standardized-client-api.ts +901 -901
- package/src/lib/startup-init.ts +276 -276
- package/src/lib/test-aware-get-token.ts +41 -41
- package/src/lib/token-expiry.ts +40 -40
- package/src/lib/token-lifecycle.ts +546 -546
- package/src/lib/token-log-id.ts +69 -69
- package/src/lib/twofa-rejection.ts +91 -91
- package/src/lib/types/api-responses.ts +336 -336
- package/src/lib/user-agent-parser.ts +252 -252
- package/src/logging/api/admin-analytics.ts +51 -51
- package/src/logging/api/audit-log.ts +53 -53
- package/src/logging/components/AdminAnalyticsLayout.tsx +49 -49
- package/src/logging/components/AuditLogViewer.tsx +125 -125
- package/src/logging/components/ErrorMetricsCard.tsx +98 -98
- package/src/logging/components/HealthMetricsCard.tsx +70 -70
- package/src/logging/hooks/useAdminAnalytics.ts +22 -22
- package/src/logging/hooks/useAuditLog.ts +24 -24
- package/src/logging/hooks/useErrorMetrics.ts +40 -40
- package/src/logging/hooks/useHealthMetrics.ts +44 -44
- package/src/logging/index.ts +18 -18
- package/src/logging/types/analytics.ts +81 -81
- package/src/logging/types/audit.ts +31 -31
- package/src/logging/types/index.ts +3 -3
- package/src/middleware/create-middleware.ts +1141 -1141
- package/src/middleware/rbac-check.ts +279 -279
- package/src/middleware/twofa-presets.ts +224 -224
- package/src/models/DecodedAccessToken.ts +16 -16
- package/src/models/SessionModel.ts +331 -331
- package/src/pages/admin-login/page.tsx +111 -111
- package/src/pages/admin-page-permissions/PagePermissionsAdminPage.tsx +527 -527
- package/src/pages/admin-page-permissions/index.ts +7 -7
- package/src/pages/admin-roles/RolesAdminPage.tsx +533 -533
- package/src/pages/admin-roles/index.ts +9 -9
- package/src/pages/admin-roles/modals.tsx +469 -469
- package/src/pages/client-admin/ClientSiteAdminPage.tsx +382 -382
- package/src/pages/client-admin/index.ts +33 -33
- package/src/pages/coming-soon/page.tsx +83 -83
- package/src/pages/login/page.tsx +338 -338
- package/src/pages/onboarding/index.ts +11 -11
- package/src/pages/onboarding/page.tsx +212 -212
- package/src/pages/profile/EnhancedProfilePage.tsx +514 -514
- package/src/pages/profile/index.ts +9 -9
- package/src/pages/profile/page.tsx +166 -166
- package/src/pages/recovery/page.tsx +267 -267
- package/src/pages/roles/MyRolesPage.tsx +211 -211
- package/src/pages/roles/components.tsx +294 -294
- package/src/pages/roles/index.ts +17 -17
- package/src/pages/security/EnhancedSecurityPage.tsx +660 -660
- package/src/pages/security/index.ts +12 -12
- package/src/pages/security/page.tsx +507 -507
- package/src/pages/service-unavailable/page.tsx +63 -63
- package/src/pages/settings/EnhancedSettingsPage.tsx +642 -642
- package/src/pages/settings/index.ts +9 -9
- package/src/pages/settings/page.tsx +47 -47
- package/src/pages/showcase/ShowcasePage.tsx +532 -532
- package/src/pages/showcase/index.ts +13 -13
- package/src/pages/test-env/EmergencyLogoutPage.tsx +192 -192
- package/src/pages/test-env/JwtInspectPage.tsx +449 -449
- package/src/pages/test-env/RefreshTokenPage.tsx +178 -178
- package/src/pages/test-env/TestEnvPage.tsx +130 -130
- package/src/pages/test-env/guarded.tsx +81 -81
- package/src/pages/test-env/index.ts +77 -77
- package/src/pages/test-env/redact-credentials.ts +96 -96
- package/src/pages/verify-code/page.tsx +746 -746
- package/src/routes/account/index.ts +31 -31
- package/src/routes/account/masked-info.ts +36 -36
- package/src/routes/account/send-code.ts +39 -39
- package/src/routes/account/update-phone.ts +13 -13
- package/src/routes/account/verify-email.ts +40 -40
- package/src/routes/account/verify-sms.ts +40 -40
- package/src/routes/auth/credential-login-email-code.ts +6 -6
- package/src/routes/auth/credential-login.ts +6 -6
- package/src/routes/auth/index.ts +22 -22
- package/src/routes/auth/logout.ts +111 -111
- package/src/routes/auth/nextauth.ts +45 -45
- package/src/routes/auth/passkey-signin.ts +13 -13
- package/src/routes/auth/refresh.ts +77 -77
- package/src/routes/auth/session-reset.ts +37 -37
- package/src/routes/auth/session.ts +261 -261
- package/src/routes/auth/settings.ts +181 -181
- package/src/routes/auth/viability.ts +519 -519
- package/src/routes/index.ts +17 -17
- package/src/routes/mfa/backup-code-verify.ts +1 -1
- package/src/routes/mfa/backup-codes.ts +10 -10
- package/src/routes/mfa/methods.ts +22 -22
- package/src/routes/mfa/totp-confirm.ts +10 -10
- package/src/routes/mfa/totp-enroll.ts +10 -10
- package/src/routes/mfa/totp-verify.ts +14 -14
- package/src/routes/onboarding/index.ts +15 -15
- package/src/routes/onboarding/send-email-code.ts +2 -2
- package/src/routes/onboarding/set-password.ts +2 -2
- package/src/routes/onboarding/verify-code.ts +2 -2
- package/src/routes/onboarding/verify-welcome-email.ts +2 -2
- package/src/routes/passkeys/list.ts +10 -10
- package/src/routes/passkeys/manage.ts +23 -23
- package/src/routes/passkeys/register-options.ts +10 -10
- package/src/routes/passkeys/register-verify.ts +10 -10
- package/src/routes/session/index.ts +7 -7
- package/src/routes/session/refresh-viability.ts +17 -17
- package/src/server/auth-guard.ts +203 -203
- package/src/server/auth.ts +486 -486
- package/src/server/decode-session.ts +309 -309
- package/src/server/slim-middleware.ts +117 -117
- package/src/server/verified-session-token.ts +103 -103
- package/src/server/with-auth.ts +93 -93
- package/src/services/signalrActivityService.ts +258 -258
- package/src/stores/authStore.ts +1900 -1900
- package/src/templates/instrumentation.ts +60 -60
- package/src/theme/ThemeProvider.tsx +39 -39
- package/src/theme/default.ts +33 -33
- package/src/theme/index.ts +31 -31
- package/src/theme/types.ts +69 -69
- package/src/theme/useTheme.ts +57 -57
- package/src/theme/utils.ts +40 -40
- package/src/types/api.ts +12 -12
- package/src/types/auth.d.ts +23 -23
- package/src/types/auth.ts +48 -48
- package/src/types/logging.ts +11 -11
- package/src/types/recovery.ts +54 -54
- package/src/utils/api.ts +401 -401
- package/src/utils/circuitBreaker.ts +40 -40
- package/src/utils/error-message.ts +108 -108
- package/src/utils/layout/reservedSpace.ts +124 -124
- package/src/utils/logout.ts +30 -30
- package/src/vibe/client.ts +878 -877
- package/src/vibe/enterprise-auth.ts +208 -208
- package/src/vibe/errors.ts +209 -209
- package/src/vibe/filters.ts +52 -0
- package/src/vibe/generic.ts +340 -339
- package/src/vibe/hooks/index.ts +367 -367
- package/src/vibe/index.ts +133 -133
- package/src/vibe/sessions.ts +925 -899
- package/src/vibe/types.ts +577 -577
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import { idpFetchJSON } from '../../lib/idp-fetch';
|
|
3
|
-
import { ENV_CONFIG } from '../../config/env';
|
|
4
|
-
import { projectIdpError } from '../../lib/safe-error-response';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Manage ONE passkey (PATCH rename / DELETE revoke, /api/Passkeys/{id},
|
|
8
|
-
* user JWT). The id arrives from the Next dynamic segment via the routes
|
|
9
|
-
* wrapper — it is never read from the body.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
function upstreamError(result: { status: number; json: unknown; attemptedRefresh: boolean }) {
|
|
13
|
-
return NextResponse.json(
|
|
14
|
-
{
|
|
15
|
-
success: false,
|
|
16
|
-
message: 'Upstream error',
|
|
17
|
-
error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: projectIdpError(result.json) },
|
|
18
|
-
meta: { attemptedRefresh: result.attemptedRefresh },
|
|
19
|
-
},
|
|
20
|
-
{ status: result.status },
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function passthrough(json: unknown) {
|
|
25
|
-
const bodyJson: any = json;
|
|
26
|
-
if (bodyJson && typeof bodyJson === 'object' && 'success' in bodyJson && 'data' in bodyJson) {
|
|
27
|
-
if (bodyJson.success === true) return NextResponse.json(bodyJson.data ?? { success: true }, { status: 200 });
|
|
28
|
-
return NextResponse.json(bodyJson, { status: 200 });
|
|
29
|
-
}
|
|
30
|
-
return NextResponse.json(bodyJson ?? { success: true }, { status: 200 });
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export async function PATCH(req: NextRequest, id: string) {
|
|
34
|
-
let body = '{}';
|
|
35
|
-
try {
|
|
36
|
-
const raw = await req.text();
|
|
37
|
-
if (raw && raw.trim().length > 0) body = raw;
|
|
38
|
-
} catch {}
|
|
39
|
-
|
|
40
|
-
const result = await idpFetchJSON(req, `${ENV_CONFIG.IDP_URL}/api/Passkeys/${encodeURIComponent(id)}`, {
|
|
41
|
-
method: 'PATCH',
|
|
42
|
-
headers: { 'Content-Type': 'application/json' },
|
|
43
|
-
body,
|
|
44
|
-
});
|
|
45
|
-
if (!result.ok) return upstreamError(result);
|
|
46
|
-
return passthrough(result.json);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export async function DELETE(req: NextRequest, id: string) {
|
|
50
|
-
const result = await idpFetchJSON(req, `${ENV_CONFIG.IDP_URL}/api/Passkeys/${encodeURIComponent(id)}`, {
|
|
51
|
-
method: 'DELETE',
|
|
52
|
-
});
|
|
53
|
-
if (!result.ok) return upstreamError(result);
|
|
54
|
-
return passthrough(result.json);
|
|
55
|
-
}
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { idpFetchJSON } from '../../lib/idp-fetch';
|
|
3
|
+
import { ENV_CONFIG } from '../../config/env';
|
|
4
|
+
import { projectIdpError } from '../../lib/safe-error-response';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Manage ONE passkey (PATCH rename / DELETE revoke, /api/Passkeys/{id},
|
|
8
|
+
* user JWT). The id arrives from the Next dynamic segment via the routes
|
|
9
|
+
* wrapper — it is never read from the body.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
function upstreamError(result: { status: number; json: unknown; attemptedRefresh: boolean }) {
|
|
13
|
+
return NextResponse.json(
|
|
14
|
+
{
|
|
15
|
+
success: false,
|
|
16
|
+
message: 'Upstream error',
|
|
17
|
+
error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: projectIdpError(result.json) },
|
|
18
|
+
meta: { attemptedRefresh: result.attemptedRefresh },
|
|
19
|
+
},
|
|
20
|
+
{ status: result.status },
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function passthrough(json: unknown) {
|
|
25
|
+
const bodyJson: any = json;
|
|
26
|
+
if (bodyJson && typeof bodyJson === 'object' && 'success' in bodyJson && 'data' in bodyJson) {
|
|
27
|
+
if (bodyJson.success === true) return NextResponse.json(bodyJson.data ?? { success: true }, { status: 200 });
|
|
28
|
+
return NextResponse.json(bodyJson, { status: 200 });
|
|
29
|
+
}
|
|
30
|
+
return NextResponse.json(bodyJson ?? { success: true }, { status: 200 });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function PATCH(req: NextRequest, id: string) {
|
|
34
|
+
let body = '{}';
|
|
35
|
+
try {
|
|
36
|
+
const raw = await req.text();
|
|
37
|
+
if (raw && raw.trim().length > 0) body = raw;
|
|
38
|
+
} catch {}
|
|
39
|
+
|
|
40
|
+
const result = await idpFetchJSON(req, `${ENV_CONFIG.IDP_URL}/api/Passkeys/${encodeURIComponent(id)}`, {
|
|
41
|
+
method: 'PATCH',
|
|
42
|
+
headers: { 'Content-Type': 'application/json' },
|
|
43
|
+
body,
|
|
44
|
+
});
|
|
45
|
+
if (!result.ok) return upstreamError(result);
|
|
46
|
+
return passthrough(result.json);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function DELETE(req: NextRequest, id: string) {
|
|
50
|
+
const result = await idpFetchJSON(req, `${ENV_CONFIG.IDP_URL}/api/Passkeys/${encodeURIComponent(id)}`, {
|
|
51
|
+
method: 'DELETE',
|
|
52
|
+
});
|
|
53
|
+
if (!result.ok) return upstreamError(result);
|
|
54
|
+
return passthrough(result.json);
|
|
55
|
+
}
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import { idpFetchJSON } from '../../lib/idp-fetch';
|
|
3
|
-
import { ENV_CONFIG } from '../../config/env';
|
|
4
|
-
import { projectIdpError } from '../../lib/safe-error-response';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Begin the passkey REGISTRATION ceremony (POST /api/Passkeys/register/options,
|
|
8
|
-
* user JWT — a credential change; the IDP may demand step-up, surfaced as-is).
|
|
9
|
-
* Returns the WebAuthn PublicKeyCredentialCreationOptions (ride the envelope
|
|
10
|
-
* `data`, per the archived hand-roll contract).
|
|
11
|
-
*/
|
|
12
|
-
export async function POST(req: NextRequest) {
|
|
13
|
-
let body = '{}';
|
|
14
|
-
try {
|
|
15
|
-
const raw = await req.text();
|
|
16
|
-
if (raw && raw.trim().length > 0) body = raw;
|
|
17
|
-
} catch {}
|
|
18
|
-
|
|
19
|
-
const result = await idpFetchJSON(req, `${ENV_CONFIG.IDP_URL}/api/Passkeys/register/options`, {
|
|
20
|
-
method: 'POST',
|
|
21
|
-
headers: { 'Content-Type': 'application/json' },
|
|
22
|
-
body,
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
if (!result.ok) {
|
|
26
|
-
return NextResponse.json(
|
|
27
|
-
{
|
|
28
|
-
success: false,
|
|
29
|
-
message: 'Upstream error',
|
|
30
|
-
error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: projectIdpError(result.json) },
|
|
31
|
-
meta: { attemptedRefresh: result.attemptedRefresh },
|
|
32
|
-
},
|
|
33
|
-
{ status: result.status },
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const bodyJson: any = result.json;
|
|
38
|
-
if (bodyJson && typeof bodyJson === 'object' && 'success' in bodyJson && 'data' in bodyJson) {
|
|
39
|
-
if (bodyJson.success === true) return NextResponse.json(bodyJson.data, { status: 200 });
|
|
40
|
-
return NextResponse.json(bodyJson, { status: 200 });
|
|
41
|
-
}
|
|
42
|
-
return NextResponse.json(bodyJson ?? {}, { status: 200 });
|
|
43
|
-
}
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { idpFetchJSON } from '../../lib/idp-fetch';
|
|
3
|
+
import { ENV_CONFIG } from '../../config/env';
|
|
4
|
+
import { projectIdpError } from '../../lib/safe-error-response';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Begin the passkey REGISTRATION ceremony (POST /api/Passkeys/register/options,
|
|
8
|
+
* user JWT — a credential change; the IDP may demand step-up, surfaced as-is).
|
|
9
|
+
* Returns the WebAuthn PublicKeyCredentialCreationOptions (ride the envelope
|
|
10
|
+
* `data`, per the archived hand-roll contract).
|
|
11
|
+
*/
|
|
12
|
+
export async function POST(req: NextRequest) {
|
|
13
|
+
let body = '{}';
|
|
14
|
+
try {
|
|
15
|
+
const raw = await req.text();
|
|
16
|
+
if (raw && raw.trim().length > 0) body = raw;
|
|
17
|
+
} catch {}
|
|
18
|
+
|
|
19
|
+
const result = await idpFetchJSON(req, `${ENV_CONFIG.IDP_URL}/api/Passkeys/register/options`, {
|
|
20
|
+
method: 'POST',
|
|
21
|
+
headers: { 'Content-Type': 'application/json' },
|
|
22
|
+
body,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
if (!result.ok) {
|
|
26
|
+
return NextResponse.json(
|
|
27
|
+
{
|
|
28
|
+
success: false,
|
|
29
|
+
message: 'Upstream error',
|
|
30
|
+
error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: projectIdpError(result.json) },
|
|
31
|
+
meta: { attemptedRefresh: result.attemptedRefresh },
|
|
32
|
+
},
|
|
33
|
+
{ status: result.status },
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const bodyJson: any = result.json;
|
|
38
|
+
if (bodyJson && typeof bodyJson === 'object' && 'success' in bodyJson && 'data' in bodyJson) {
|
|
39
|
+
if (bodyJson.success === true) return NextResponse.json(bodyJson.data, { status: 200 });
|
|
40
|
+
return NextResponse.json(bodyJson, { status: 200 });
|
|
41
|
+
}
|
|
42
|
+
return NextResponse.json(bodyJson ?? {}, { status: 200 });
|
|
43
|
+
}
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import { idpFetchJSON } from '../../lib/idp-fetch';
|
|
3
|
-
import { ENV_CONFIG } from '../../config/env';
|
|
4
|
-
import { projectIdpError } from '../../lib/safe-error-response';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Finish the passkey REGISTRATION ceremony (POST /api/Passkeys/register/verify,
|
|
8
|
-
* user JWT). Body forwarded VERBATIM — it carries the enrolment handle plus the
|
|
9
|
-
* authenticator attestation produced by navigator.credentials.create().
|
|
10
|
-
*/
|
|
11
|
-
export async function POST(req: NextRequest) {
|
|
12
|
-
let body = '{}';
|
|
13
|
-
try {
|
|
14
|
-
const raw = await req.text();
|
|
15
|
-
if (raw && raw.trim().length > 0) body = raw;
|
|
16
|
-
} catch {}
|
|
17
|
-
|
|
18
|
-
const result = await idpFetchJSON(req, `${ENV_CONFIG.IDP_URL}/api/Passkeys/register/verify`, {
|
|
19
|
-
method: 'POST',
|
|
20
|
-
headers: { 'Content-Type': 'application/json' },
|
|
21
|
-
body,
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
if (!result.ok) {
|
|
25
|
-
return NextResponse.json(
|
|
26
|
-
{
|
|
27
|
-
success: false,
|
|
28
|
-
message: 'Upstream error',
|
|
29
|
-
error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: projectIdpError(result.json) },
|
|
30
|
-
meta: { attemptedRefresh: result.attemptedRefresh },
|
|
31
|
-
},
|
|
32
|
-
{ status: result.status },
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const bodyJson: any = result.json;
|
|
37
|
-
if (bodyJson && typeof bodyJson === 'object' && 'success' in bodyJson && 'data' in bodyJson) {
|
|
38
|
-
if (bodyJson.success === true) return NextResponse.json(bodyJson.data, { status: 200 });
|
|
39
|
-
return NextResponse.json(bodyJson, { status: 200 });
|
|
40
|
-
}
|
|
41
|
-
return NextResponse.json(bodyJson ?? {}, { status: 200 });
|
|
42
|
-
}
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { idpFetchJSON } from '../../lib/idp-fetch';
|
|
3
|
+
import { ENV_CONFIG } from '../../config/env';
|
|
4
|
+
import { projectIdpError } from '../../lib/safe-error-response';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Finish the passkey REGISTRATION ceremony (POST /api/Passkeys/register/verify,
|
|
8
|
+
* user JWT). Body forwarded VERBATIM — it carries the enrolment handle plus the
|
|
9
|
+
* authenticator attestation produced by navigator.credentials.create().
|
|
10
|
+
*/
|
|
11
|
+
export async function POST(req: NextRequest) {
|
|
12
|
+
let body = '{}';
|
|
13
|
+
try {
|
|
14
|
+
const raw = await req.text();
|
|
15
|
+
if (raw && raw.trim().length > 0) body = raw;
|
|
16
|
+
} catch {}
|
|
17
|
+
|
|
18
|
+
const result = await idpFetchJSON(req, `${ENV_CONFIG.IDP_URL}/api/Passkeys/register/verify`, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
headers: { 'Content-Type': 'application/json' },
|
|
21
|
+
body,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (!result.ok) {
|
|
25
|
+
return NextResponse.json(
|
|
26
|
+
{
|
|
27
|
+
success: false,
|
|
28
|
+
message: 'Upstream error',
|
|
29
|
+
error: { code: 'UPSTREAM_SERVICE_ERROR', status: result.status, details: projectIdpError(result.json) },
|
|
30
|
+
meta: { attemptedRefresh: result.attemptedRefresh },
|
|
31
|
+
},
|
|
32
|
+
{ status: result.status },
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const bodyJson: any = result.json;
|
|
37
|
+
if (bodyJson && typeof bodyJson === 'object' && 'success' in bodyJson && 'data' in bodyJson) {
|
|
38
|
+
if (bodyJson.success === true) return NextResponse.json(bodyJson.data, { status: 200 });
|
|
39
|
+
return NextResponse.json(bodyJson, { status: 200 });
|
|
40
|
+
}
|
|
41
|
+
return NextResponse.json(bodyJson ?? {}, { status: 200 });
|
|
42
|
+
}
|
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
-
import { getSession, isRefreshInProgress } from '../../lib/session-store';
|
|
3
|
-
import { checkRefreshViability } from '../../lib/refresh-token-validator';
|
|
4
|
-
import { getTokenTestAware } from '../../lib/test-aware-get-token';
|
|
5
|
-
import { logger } from '../../config/logger';
|
|
6
|
-
import { tokenLogId } from '../../lib/token-log-id';
|
|
7
|
-
import { resolveSessionState } from '../../server/auth';
|
|
8
|
-
|
|
9
|
-
export async function GET(req: NextRequest) {
|
|
10
|
-
try {
|
|
11
|
-
const sessionToken = req.nextUrl.searchParams.get('token');
|
|
12
|
-
let finalSessionToken = sessionToken;
|
|
13
|
-
if (!finalSessionToken && process.env.TEST_MODE !== 'true') {
|
|
14
|
-
// PAY-2216: outside TEST_MODE getTokenTestAware is getSession(), which answered null for a store outage AND
|
|
15
|
-
// for a deleted session, so this route said not_logged_in to both and its own session_not_found arm (below)
|
|
16
|
-
// was unreachable from a cookie. Ask for the state instead. Same rules as routes/auth/viability.ts:
|
|
17
|
-
// 'unknown' never reads as logged out or stale; 'missing' requires a verified cookie.
|
|
18
|
-
const sessionState = await resolveSessionState(req);
|
|
19
|
-
if (sessionState.state === 'unknown') {
|
|
20
|
-
logger.warn('[REFRESH-VIABILITY] Session store unavailable - session state unknown');
|
|
21
|
-
return NextResponse.json({ canRefresh: false, reason: 'store_unavailable', error: 'Session store unavailable', code: 'STORE_UNAVAILABLE' }, { status: 500 });
|
|
22
|
-
}
|
|
23
|
-
if (sessionState.state === 'missing') {
|
|
24
|
-
return NextResponse.json({ canRefresh: false, reason: 'session_not_found', sessionTokenId: tokenLogId(sessionState.sessionToken) }, { status: 200 });
|
|
25
|
-
}
|
|
26
|
-
if (sessionState.state === 'live') {
|
|
27
|
-
finalSessionToken = sessionState.session?.session?.token ?? null;
|
|
28
|
-
}
|
|
29
|
-
} else if (!finalSessionToken) {
|
|
30
|
-
const token = await getTokenTestAware(req);
|
|
31
|
-
// Support both field names: sessionToken (auth.ts JWT) and redisSessionId (legacy)
|
|
32
|
-
finalSessionToken = (token?.sessionToken || token?.redisSessionId) as string;
|
|
33
|
-
}
|
|
34
|
-
if (!finalSessionToken) {
|
|
35
|
-
return NextResponse.json({ canRefresh: false, reason: 'not_logged_in', sessionTokenId: null }, { status: 200 });
|
|
36
|
-
}
|
|
37
|
-
const refreshInProgress = await isRefreshInProgress(finalSessionToken);
|
|
38
|
-
if (refreshInProgress) {
|
|
39
|
-
// Still need to get session data for twoFactorComplete even when refresh is in progress
|
|
40
|
-
const sessionData = await getSession(finalSessionToken);
|
|
41
|
-
logger.info('[REFRESH-VIABILITY] Refresh already in progress, telling middleware to wait', { sessionToken: tokenLogId(finalSessionToken) });
|
|
42
|
-
return NextResponse.json({ canRefresh: true, reason: 'refresh_in_progress', refreshInProgress: true, sessionTokenId: tokenLogId(finalSessionToken), twoFactorComplete: sessionData?.mfaVerified ?? false }, { status: 200 });
|
|
43
|
-
}
|
|
44
|
-
const sessionData = await getSession(finalSessionToken);
|
|
45
|
-
if (!sessionData) {
|
|
46
|
-
return NextResponse.json({ canRefresh: false, reason: 'session_not_found', sessionTokenId: tokenLogId(finalSessionToken) }, { status: 200 });
|
|
47
|
-
}
|
|
48
|
-
const viabilityCheck = checkRefreshViability(sessionData);
|
|
49
|
-
return NextResponse.json({ canRefresh: viabilityCheck.canRefresh, reason: viabilityCheck.reason, timeRemaining: viabilityCheck.timeRemaining, expiresAt: viabilityCheck.expiresAt, accessTokenExpired: viabilityCheck.accessTokenExpired, accessTokenTimeRemaining: viabilityCheck.accessTokenTimeRemaining, sessionTokenId: tokenLogId(finalSessionToken), twoFactorComplete: sessionData.mfaVerified ?? false, userId: sessionData.userId, refreshInProgress: false });
|
|
50
|
-
} catch (error) {
|
|
51
|
-
const correlationId = globalThis.crypto.randomUUID();
|
|
52
|
-
logger.error('[REFRESH-VIABILITY] Error checking refresh viability', { correlationId, error: error instanceof Error ? error.message : String(error) });
|
|
53
|
-
// PAY-1438: the exception text stays in the log above; the caller gets the id.
|
|
54
|
-
return NextResponse.json({ canRefresh: false, reason: 'check_error', error: 'Failed to check refresh viability', code: 'INTERNAL_ERROR', correlationId }, { status: 500 });
|
|
55
|
-
}
|
|
56
|
-
}
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
import { getSession, isRefreshInProgress } from '../../lib/session-store';
|
|
3
|
+
import { checkRefreshViability } from '../../lib/refresh-token-validator';
|
|
4
|
+
import { getTokenTestAware } from '../../lib/test-aware-get-token';
|
|
5
|
+
import { logger } from '../../config/logger';
|
|
6
|
+
import { tokenLogId } from '../../lib/token-log-id';
|
|
7
|
+
import { resolveSessionState } from '../../server/auth';
|
|
8
|
+
|
|
9
|
+
export async function GET(req: NextRequest) {
|
|
10
|
+
try {
|
|
11
|
+
const sessionToken = req.nextUrl.searchParams.get('token');
|
|
12
|
+
let finalSessionToken = sessionToken;
|
|
13
|
+
if (!finalSessionToken && process.env.TEST_MODE !== 'true') {
|
|
14
|
+
// PAY-2216: outside TEST_MODE getTokenTestAware is getSession(), which answered null for a store outage AND
|
|
15
|
+
// for a deleted session, so this route said not_logged_in to both and its own session_not_found arm (below)
|
|
16
|
+
// was unreachable from a cookie. Ask for the state instead. Same rules as routes/auth/viability.ts:
|
|
17
|
+
// 'unknown' never reads as logged out or stale; 'missing' requires a verified cookie.
|
|
18
|
+
const sessionState = await resolveSessionState(req);
|
|
19
|
+
if (sessionState.state === 'unknown') {
|
|
20
|
+
logger.warn('[REFRESH-VIABILITY] Session store unavailable - session state unknown');
|
|
21
|
+
return NextResponse.json({ canRefresh: false, reason: 'store_unavailable', error: 'Session store unavailable', code: 'STORE_UNAVAILABLE' }, { status: 500 });
|
|
22
|
+
}
|
|
23
|
+
if (sessionState.state === 'missing') {
|
|
24
|
+
return NextResponse.json({ canRefresh: false, reason: 'session_not_found', sessionTokenId: tokenLogId(sessionState.sessionToken) }, { status: 200 });
|
|
25
|
+
}
|
|
26
|
+
if (sessionState.state === 'live') {
|
|
27
|
+
finalSessionToken = sessionState.session?.session?.token ?? null;
|
|
28
|
+
}
|
|
29
|
+
} else if (!finalSessionToken) {
|
|
30
|
+
const token = await getTokenTestAware(req);
|
|
31
|
+
// Support both field names: sessionToken (auth.ts JWT) and redisSessionId (legacy)
|
|
32
|
+
finalSessionToken = (token?.sessionToken || token?.redisSessionId) as string;
|
|
33
|
+
}
|
|
34
|
+
if (!finalSessionToken) {
|
|
35
|
+
return NextResponse.json({ canRefresh: false, reason: 'not_logged_in', sessionTokenId: null }, { status: 200 });
|
|
36
|
+
}
|
|
37
|
+
const refreshInProgress = await isRefreshInProgress(finalSessionToken);
|
|
38
|
+
if (refreshInProgress) {
|
|
39
|
+
// Still need to get session data for twoFactorComplete even when refresh is in progress
|
|
40
|
+
const sessionData = await getSession(finalSessionToken);
|
|
41
|
+
logger.info('[REFRESH-VIABILITY] Refresh already in progress, telling middleware to wait', { sessionToken: tokenLogId(finalSessionToken) });
|
|
42
|
+
return NextResponse.json({ canRefresh: true, reason: 'refresh_in_progress', refreshInProgress: true, sessionTokenId: tokenLogId(finalSessionToken), twoFactorComplete: sessionData?.mfaVerified ?? false }, { status: 200 });
|
|
43
|
+
}
|
|
44
|
+
const sessionData = await getSession(finalSessionToken);
|
|
45
|
+
if (!sessionData) {
|
|
46
|
+
return NextResponse.json({ canRefresh: false, reason: 'session_not_found', sessionTokenId: tokenLogId(finalSessionToken) }, { status: 200 });
|
|
47
|
+
}
|
|
48
|
+
const viabilityCheck = checkRefreshViability(sessionData);
|
|
49
|
+
return NextResponse.json({ canRefresh: viabilityCheck.canRefresh, reason: viabilityCheck.reason, timeRemaining: viabilityCheck.timeRemaining, expiresAt: viabilityCheck.expiresAt, accessTokenExpired: viabilityCheck.accessTokenExpired, accessTokenTimeRemaining: viabilityCheck.accessTokenTimeRemaining, sessionTokenId: tokenLogId(finalSessionToken), twoFactorComplete: sessionData.mfaVerified ?? false, userId: sessionData.userId, refreshInProgress: false });
|
|
50
|
+
} catch (error) {
|
|
51
|
+
const correlationId = globalThis.crypto.randomUUID();
|
|
52
|
+
logger.error('[REFRESH-VIABILITY] Error checking refresh viability', { correlationId, error: error instanceof Error ? error.message : String(error) });
|
|
53
|
+
// PAY-1438: the exception text stays in the log above; the caller gets the id.
|
|
54
|
+
return NextResponse.json({ canRefresh: false, reason: 'check_error', error: 'Failed to check refresh viability', code: 'INTERNAL_ERROR', correlationId }, { status: 500 });
|
|
55
|
+
}
|
|
56
|
+
}
|