@payez/next-mvp 3.9.0 → 4.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.
- package/dist/api/auth-handler.d.ts +1 -2
- package/dist/api/auth-handler.js +9 -9
- package/dist/api-handlers/account/change-password.js +110 -112
- package/dist/api-handlers/admin/analytics.d.ts +19 -20
- package/dist/api-handlers/admin/analytics.js +378 -379
- package/dist/api-handlers/admin/audit.d.ts +19 -20
- package/dist/api-handlers/admin/audit.js +213 -214
- package/dist/api-handlers/admin/index.d.ts +21 -22
- package/dist/api-handlers/admin/index.js +42 -43
- package/dist/api-handlers/admin/redis-sessions.d.ts +35 -36
- package/dist/api-handlers/admin/redis-sessions.js +203 -204
- package/dist/api-handlers/admin/sessions.d.ts +20 -21
- package/dist/api-handlers/admin/sessions.js +283 -284
- package/dist/api-handlers/admin/site-logs.d.ts +45 -46
- package/dist/api-handlers/admin/site-logs.js +317 -318
- package/dist/api-handlers/admin/stats.d.ts +20 -21
- package/dist/api-handlers/admin/stats.js +239 -240
- package/dist/api-handlers/admin/users.d.ts +19 -20
- package/dist/api-handlers/admin/users.js +221 -222
- package/dist/api-handlers/admin/vibe-data.d.ts +79 -80
- package/dist/api-handlers/admin/vibe-data.js +267 -268
- package/dist/api-handlers/auth/refresh.js +633 -635
- package/dist/api-handlers/auth/signout.js +186 -187
- package/dist/api-handlers/auth/status.js +4 -7
- package/dist/api-handlers/auth/update-session.d.ts +1 -1
- package/dist/api-handlers/auth/update-session.js +12 -14
- package/dist/api-handlers/auth/verify-code.d.ts +43 -43
- package/dist/api-handlers/auth/verify-code.js +90 -94
- package/dist/api-handlers/session/viability.js +114 -146
- package/dist/api-handlers/test/force-expire.js +59 -65
- package/dist/auth/auth-decision.js +182 -182
- package/dist/auth/better-auth.d.ts +3 -6
- package/dist/auth/better-auth.js +3 -6
- package/dist/auth/route-config.js +2 -2
- package/dist/auth/utils/token-utils.d.ts +83 -84
- package/dist/auth/utils/token-utils.js +218 -219
- package/dist/client/AuthContext.js +115 -112
- package/dist/client/better-auth-client.d.ts +1020 -961
- package/dist/client/better-auth-client.js +54 -7
- package/dist/client/fetch-with-auth.js +2 -2
- package/dist/components/SessionSync.js +121 -119
- package/dist/components/account/MobileNavDrawer.js +64 -64
- package/dist/components/account/UserAvatarMenu.js +91 -88
- package/dist/components/admin/VibeAdminLayout.js +71 -69
- package/dist/hooks/useAuth.js +9 -7
- package/dist/hooks/useAuthSettings.js +93 -93
- package/dist/hooks/useAvailableProviders.d.ts +43 -45
- package/dist/hooks/useAvailableProviders.js +112 -108
- package/dist/hooks/useSessionExpiration.d.ts +2 -3
- package/dist/hooks/useSessionExpiration.js +2 -2
- package/dist/hooks/useViabilitySession.js +3 -2
- package/dist/index.js +4 -6
- package/dist/lib/app-slug.d.ts +95 -95
- package/dist/lib/app-slug.js +172 -172
- package/dist/lib/standardized-client-api.js +10 -5
- package/dist/lib/startup-init.js +21 -25
- package/dist/lib/test-aware-get-token.js +86 -81
- package/dist/lib/token-lifecycle.d.ts +78 -52
- package/dist/lib/token-lifecycle.js +360 -398
- package/dist/pages/admin-login/page.js +73 -83
- package/dist/pages/client-admin/ClientSiteAdminPage.js +179 -177
- package/dist/pages/login/page.js +202 -211
- package/dist/pages/showcase/ShowcasePage.js +142 -140
- package/dist/pages/test-env/EmergencyLogoutPage.js +99 -98
- package/dist/pages/test-env/JwtInspectPage.js +116 -114
- package/dist/pages/test-env/RefreshTokenPage.js +4 -2
- package/dist/pages/test-env/TestEnvPage.js +51 -49
- package/dist/pages/verify-code/page.js +412 -408
- package/dist/routes/auth/logout.d.ts +31 -31
- package/dist/routes/auth/logout.js +98 -113
- package/dist/routes/auth/nextauth.d.ts +14 -11
- package/dist/routes/auth/nextauth.js +25 -57
- package/dist/routes/auth/session.js +157 -179
- package/dist/routes/auth/viability.js +190 -201
- package/dist/server/auth.d.ts +50 -0
- package/dist/server/auth.js +62 -0
- package/dist/stores/authStore.js +19 -23
- package/dist/utils/logout.js +5 -5
- package/package.json +1 -3
- package/src/api/auth-handler.ts +550 -549
- package/src/api-handlers/account/change-password.ts +5 -8
- package/src/api-handlers/admin/analytics.ts +4 -6
- package/src/api-handlers/admin/audit.ts +5 -7
- package/src/api-handlers/admin/index.ts +1 -2
- package/src/api-handlers/admin/redis-sessions.ts +6 -8
- package/src/api-handlers/admin/sessions.ts +5 -7
- package/src/api-handlers/admin/site-logs.ts +8 -10
- package/src/api-handlers/admin/stats.ts +4 -6
- package/src/api-handlers/admin/users.ts +5 -7
- package/src/api-handlers/admin/vibe-data.ts +10 -12
- package/src/api-handlers/auth/refresh.ts +5 -7
- package/src/api-handlers/auth/signout.ts +5 -6
- package/src/api-handlers/auth/status.ts +4 -7
- package/src/api-handlers/auth/update-session.ts +123 -125
- package/src/api-handlers/auth/verify-code.ts +9 -13
- package/src/api-handlers/session/viability.ts +10 -47
- package/src/api-handlers/test/force-expire.ts +4 -11
- package/src/auth/auth-decision.ts +1 -1
- package/src/auth/better-auth.ts +138 -141
- package/src/auth/route-config.ts +219 -219
- package/src/auth/utils/token-utils.ts +0 -1
- package/src/client/AuthContext.tsx +6 -2
- package/src/client/better-auth-client.ts +54 -7
- package/src/client/fetch-with-auth.ts +47 -47
- package/src/components/SessionSync.tsx +6 -5
- package/src/components/account/MobileNavDrawer.tsx +3 -3
- package/src/components/account/UserAvatarMenu.tsx +6 -3
- package/src/components/admin/VibeAdminLayout.tsx +4 -2
- package/src/config/logger.ts +1 -1
- package/src/hooks/useAuth.ts +117 -115
- package/src/hooks/useAuthSettings.ts +2 -2
- package/src/hooks/useAvailableProviders.ts +9 -5
- package/src/hooks/useSessionExpiration.ts +101 -102
- package/src/hooks/useViabilitySession.ts +336 -335
- package/src/index.ts +60 -63
- package/src/lib/api-handler.ts +0 -1
- package/src/lib/app-slug.ts +6 -6
- package/src/lib/standardized-client-api.ts +901 -895
- package/src/lib/startup-init.ts +243 -247
- package/src/lib/test-aware-get-token.ts +22 -12
- package/src/lib/token-lifecycle.ts +12 -53
- package/src/pages/admin-login/page.tsx +9 -17
- package/src/pages/client-admin/ClientSiteAdminPage.tsx +4 -2
- package/src/pages/login/page.tsx +21 -28
- package/src/pages/showcase/ShowcasePage.tsx +4 -2
- package/src/pages/test-env/EmergencyLogoutPage.tsx +7 -6
- package/src/pages/test-env/JwtInspectPage.tsx +5 -3
- package/src/pages/test-env/RefreshTokenPage.tsx +157 -155
- package/src/pages/test-env/TestEnvPage.tsx +4 -2
- package/src/pages/verify-code/page.tsx +10 -6
- package/src/routes/auth/logout.ts +7 -25
- package/src/routes/auth/nextauth.ts +45 -71
- package/src/routes/auth/session.ts +25 -50
- package/src/routes/auth/viability.ts +7 -19
- package/src/server/auth.ts +60 -0
- package/src/stores/authStore.ts +1899 -1904
- package/src/utils/logout.ts +30 -30
- package/src/auth/auth-options.ts +0 -237
- package/src/auth/callbacks/index.ts +0 -7
- package/src/auth/callbacks/jwt.ts +0 -382
- package/src/auth/callbacks/session.ts +0 -243
- package/src/auth/callbacks/signin.ts +0 -56
- package/src/auth/events/index.ts +0 -5
- package/src/auth/events/signout.ts +0 -33
- package/src/auth/providers/credentials.ts +0 -256
- package/src/auth/providers/index.ts +0 -6
- package/src/auth/providers/oauth.ts +0 -114
- package/src/lib/nextauth-secret.ts +0 -121
- package/src/types/next-auth.d.ts +0 -15
|
@@ -1,201 +1,190 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Ready-to-Use Session Viability Route
|
|
4
|
-
*
|
|
5
|
-
* Checks if the current session is viable (valid and not expired).
|
|
6
|
-
* Used by client-side code to determine if a refresh is needed.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* ```typescript
|
|
10
|
-
* // app/api/session/viability/route.ts
|
|
11
|
-
* export { GET } from '@payez/next-mvp/routes/auth/viability';
|
|
12
|
-
* ```
|
|
13
|
-
*
|
|
14
|
-
* @version 2.0.0
|
|
15
|
-
* @since auth-ready-v2
|
|
16
|
-
*/
|
|
17
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.GET = GET;
|
|
19
|
-
const server_1 = require("next/server");
|
|
20
|
-
const
|
|
21
|
-
const session_store_1 = require("../../lib/session-store");
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
catch (error) {
|
|
192
|
-
console.error('[VIABILITY_ROUTE] Error checking session viability:', error);
|
|
193
|
-
return server_1.NextResponse.json({
|
|
194
|
-
viable: false,
|
|
195
|
-
needsRefresh: false,
|
|
196
|
-
authenticated: false,
|
|
197
|
-
error: 'Failed to check session',
|
|
198
|
-
details: error instanceof Error ? error.message : 'Unknown error'
|
|
199
|
-
}, { status: 500 });
|
|
200
|
-
}
|
|
201
|
-
}
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Ready-to-Use Session Viability Route
|
|
4
|
+
*
|
|
5
|
+
* Checks if the current session is viable (valid and not expired).
|
|
6
|
+
* Used by client-side code to determine if a refresh is needed.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* // app/api/session/viability/route.ts
|
|
11
|
+
* export { GET } from '@payez/next-mvp/routes/auth/viability';
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @version 2.0.0
|
|
15
|
+
* @since auth-ready-v2
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.GET = GET;
|
|
19
|
+
const server_1 = require("next/server");
|
|
20
|
+
const auth_1 = require("../../server/auth");
|
|
21
|
+
const session_store_1 = require("../../lib/session-store");
|
|
22
|
+
const idp_client_config_1 = require("../../lib/idp-client-config");
|
|
23
|
+
/**
|
|
24
|
+
* Get tenant-wide 2FA requirement from cached client config (from broker handshake)
|
|
25
|
+
*/
|
|
26
|
+
async function getTenantRequiresTwoFactor() {
|
|
27
|
+
try {
|
|
28
|
+
const config = await (0, idp_client_config_1.getIDPClientConfig)();
|
|
29
|
+
return config.authSettings?.require2FA ?? true; // Default to true for security
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
console.warn('[VIABILITY] Could not get client config, defaulting tenantRequiresTwoFactor to true');
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* GET /api/session/viability - Check if session is viable
|
|
38
|
+
*
|
|
39
|
+
* Returns:
|
|
40
|
+
* - viable: boolean - Whether the session can be used
|
|
41
|
+
* - needsRefresh: boolean - Whether a refresh is recommended
|
|
42
|
+
* - expiresIn: number - Seconds until token expires
|
|
43
|
+
*/
|
|
44
|
+
async function GET(req) {
|
|
45
|
+
try {
|
|
46
|
+
const baSession = await (0, auth_1.getSession)(req);
|
|
47
|
+
if (!baSession) {
|
|
48
|
+
return server_1.NextResponse.json({
|
|
49
|
+
viable: false,
|
|
50
|
+
needsRefresh: false,
|
|
51
|
+
authenticated: false,
|
|
52
|
+
reason: 'No session found'
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const token = baSession;
|
|
56
|
+
const sessionToken = baSession.session?.token;
|
|
57
|
+
const session = sessionToken ? await (0, session_store_1.getSession)(sessionToken) : null;
|
|
58
|
+
// CRITICAL: Detect stale cookie state (JWT exists but Redis session missing)
|
|
59
|
+
if (sessionToken && !session) {
|
|
60
|
+
console.warn('[VIABILITY] Stale cookie detected - session not in Redis');
|
|
61
|
+
return server_1.NextResponse.json({
|
|
62
|
+
viable: false,
|
|
63
|
+
needsRefresh: false,
|
|
64
|
+
authenticated: false,
|
|
65
|
+
sessionToken, // Return sessionToken so middleware can detect and clear stale cookie
|
|
66
|
+
reason: 'Stale session - cookie exists but session not found in Redis'
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// Check access token expiry
|
|
70
|
+
const now = Math.floor(Date.now() / 1000);
|
|
71
|
+
const accessTokenExpires = token.accessTokenExpires || token.exp;
|
|
72
|
+
if (!accessTokenExpires) {
|
|
73
|
+
// No expiry info, assume viable but recommend refresh
|
|
74
|
+
const tenantRequiresTwoFactor = await getTenantRequiresTwoFactor();
|
|
75
|
+
// CRITICAL: Check if MFA has expired (2FA TTL enforcement)
|
|
76
|
+
const mfaExpiresAt = session?.mfaExpiresAt || 0;
|
|
77
|
+
const mfaExpired = mfaExpiresAt > 0 && mfaExpiresAt < Date.now();
|
|
78
|
+
// Check mfaVerified (normalized name) with fallback to twoFactorComplete for compatibility
|
|
79
|
+
const mfaVerifiedInSession = session?.mfaVerified ?? session?.twoFactorComplete ?? false;
|
|
80
|
+
// User has completed 2FA requirements if: they verified AND it hasn't expired
|
|
81
|
+
const userHasCompletedTenantTwoFactorRequirements = mfaVerifiedInSession && !mfaExpired;
|
|
82
|
+
// userStillNeedsTwoFactor = inverse of completed (matches session callback logic)
|
|
83
|
+
const userStillNeedsTwoFactor = !userHasCompletedTenantTwoFactorRequirements;
|
|
84
|
+
return server_1.NextResponse.json({
|
|
85
|
+
viable: true,
|
|
86
|
+
needsRefresh: true,
|
|
87
|
+
authenticated: true,
|
|
88
|
+
sessionToken,
|
|
89
|
+
// Clear names for middleware decision-making
|
|
90
|
+
tenantRequiresTwoFactor,
|
|
91
|
+
userHasCompletedTenantTwoFactorRequirements,
|
|
92
|
+
userStillNeedsTwoFactor,
|
|
93
|
+
// Legacy field names for backwards compatibility
|
|
94
|
+
requires2FA: tenantRequiresTwoFactor,
|
|
95
|
+
twoFactorComplete: userHasCompletedTenantTwoFactorRequirements,
|
|
96
|
+
accessTokenExpired: false,
|
|
97
|
+
reason: 'No expiry information'
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
// Convert to seconds if needed
|
|
101
|
+
const expiryTime = accessTokenExpires > 1000000000000
|
|
102
|
+
? Math.floor(accessTokenExpires / 1000)
|
|
103
|
+
: accessTokenExpires;
|
|
104
|
+
const expiresIn = expiryTime - now;
|
|
105
|
+
const isExpired = expiresIn <= 0;
|
|
106
|
+
const needsRefresh = expiresIn <= 300; // 5 minutes buffer
|
|
107
|
+
// Check if we have refresh capability (check normalized field name first)
|
|
108
|
+
const hasRefreshToken = !!(session?.idpRefreshToken || session?.refreshToken || token.refreshToken);
|
|
109
|
+
// CLEAR NAMING: Tenant-wide 2FA requirement from client config
|
|
110
|
+
const tenantRequiresTwoFactor = await getTenantRequiresTwoFactor();
|
|
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 = session?.mfaExpiresAt || 0;
|
|
115
|
+
const mfaExpired = mfaExpiresAt > 0 && mfaExpiresAt < Date.now();
|
|
116
|
+
// Check mfaVerified (normalized name) with fallback to twoFactorComplete for compatibility
|
|
117
|
+
const mfaVerifiedInSession = session?.mfaVerified ?? session?.twoFactorComplete ?? false;
|
|
118
|
+
// DEBUG: Log what we're reading from the session
|
|
119
|
+
console.log('[VIABILITY] Session 2FA state:', {
|
|
120
|
+
sessionToken: sessionToken?.substring(0, 8) + '...',
|
|
121
|
+
'session.mfaVerified': session?.mfaVerified,
|
|
122
|
+
'session.twoFactorComplete': session?.twoFactorComplete,
|
|
123
|
+
mfaVerifiedInSession,
|
|
124
|
+
mfaExpiresAt,
|
|
125
|
+
mfaExpired,
|
|
126
|
+
hasRefreshToken,
|
|
127
|
+
'session.idpRefreshToken': !!session?.idpRefreshToken,
|
|
128
|
+
'session.refreshToken': !!session?.refreshToken,
|
|
129
|
+
});
|
|
130
|
+
// CLEAR NAMING: User has completed 2FA requirements if: they verified AND it hasn't expired
|
|
131
|
+
const userHasCompletedTenantTwoFactorRequirements = mfaVerifiedInSession && !mfaExpired;
|
|
132
|
+
// userStillNeedsTwoFactor = inverse of completed (matches session callback logic)
|
|
133
|
+
const userStillNeedsTwoFactor = !userHasCompletedTenantTwoFactorRequirements;
|
|
134
|
+
if (mfaExpired && mfaVerifiedInSession) {
|
|
135
|
+
console.warn('[VIABILITY] MFA expired - forcing 2FA re-verification');
|
|
136
|
+
}
|
|
137
|
+
if (isExpired) {
|
|
138
|
+
return server_1.NextResponse.json({
|
|
139
|
+
viable: false,
|
|
140
|
+
needsRefresh: hasRefreshToken,
|
|
141
|
+
expiresIn: 0,
|
|
142
|
+
hasRefreshToken,
|
|
143
|
+
authenticated: true,
|
|
144
|
+
sessionToken,
|
|
145
|
+
// Clear names
|
|
146
|
+
tenantRequiresTwoFactor,
|
|
147
|
+
userHasCompletedTenantTwoFactorRequirements,
|
|
148
|
+
userStillNeedsTwoFactor,
|
|
149
|
+
// Legacy names for backwards compatibility
|
|
150
|
+
requires2FA: tenantRequiresTwoFactor,
|
|
151
|
+
twoFactorComplete: userHasCompletedTenantTwoFactorRequirements,
|
|
152
|
+
accessTokenExpired: true,
|
|
153
|
+
reason: 'Token expired',
|
|
154
|
+
// RBAC fields
|
|
155
|
+
roles: session?.roles || [],
|
|
156
|
+
clientId: session?.idpClientId || process.env.IDP_CLIENT_ID || '',
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return server_1.NextResponse.json({
|
|
160
|
+
viable: true,
|
|
161
|
+
needsRefresh,
|
|
162
|
+
expiresIn,
|
|
163
|
+
hasRefreshToken,
|
|
164
|
+
authenticated: true,
|
|
165
|
+
sessionToken,
|
|
166
|
+
// Clear names
|
|
167
|
+
tenantRequiresTwoFactor,
|
|
168
|
+
userHasCompletedTenantTwoFactorRequirements,
|
|
169
|
+
userStillNeedsTwoFactor,
|
|
170
|
+
// Legacy names for backwards compatibility
|
|
171
|
+
requires2FA: tenantRequiresTwoFactor,
|
|
172
|
+
twoFactorComplete: userHasCompletedTenantTwoFactorRequirements,
|
|
173
|
+
accessTokenExpired: false,
|
|
174
|
+
expiresAt: new Date(expiryTime * 1000).toISOString(),
|
|
175
|
+
// RBAC fields
|
|
176
|
+
roles: session?.roles || [],
|
|
177
|
+
clientId: session?.idpClientId || process.env.IDP_CLIENT_ID || '',
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
console.error('[VIABILITY_ROUTE] Error checking session viability:', error);
|
|
182
|
+
return server_1.NextResponse.json({
|
|
183
|
+
viable: false,
|
|
184
|
+
needsRefresh: false,
|
|
185
|
+
authenticated: false,
|
|
186
|
+
error: 'Failed to check session',
|
|
187
|
+
details: error instanceof Error ? error.message : 'Unknown error'
|
|
188
|
+
}, { status: 500 });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side auth utilities for Better Auth (v4.0)
|
|
3
|
+
*
|
|
4
|
+
* Replaces:
|
|
5
|
+
* - getToken() from next-auth/jwt
|
|
6
|
+
* - getServerSession() from next-auth
|
|
7
|
+
*
|
|
8
|
+
* All server-side auth flows go through the Better Auth instance.
|
|
9
|
+
*/
|
|
10
|
+
import 'server-only';
|
|
11
|
+
/**
|
|
12
|
+
* Get the initialized Better Auth instance (singleton).
|
|
13
|
+
*/
|
|
14
|
+
export declare function getAuthInstance(): Promise<import("better-auth/types").Auth<{
|
|
15
|
+
secret: string;
|
|
16
|
+
socialProviders: Record<string, import("../auth/better-auth").BetterAuthSocialProvider>;
|
|
17
|
+
trustedOrigins: string[];
|
|
18
|
+
session: {
|
|
19
|
+
cookieCache: {
|
|
20
|
+
enabled: true;
|
|
21
|
+
maxAge: number;
|
|
22
|
+
refreshCache: true;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
plugins: [{
|
|
26
|
+
id: "next-cookies";
|
|
27
|
+
hooks: {
|
|
28
|
+
before: {
|
|
29
|
+
matcher(ctx: import("@better-auth/core").HookEndpointContext): boolean;
|
|
30
|
+
handler: (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>;
|
|
31
|
+
}[];
|
|
32
|
+
after: {
|
|
33
|
+
matcher(ctx: import("@better-auth/core").HookEndpointContext): true;
|
|
34
|
+
handler: (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>;
|
|
35
|
+
}[];
|
|
36
|
+
};
|
|
37
|
+
}];
|
|
38
|
+
}>>;
|
|
39
|
+
/**
|
|
40
|
+
* Get the current session from a request.
|
|
41
|
+
* Replaces getToken() and getServerSession().
|
|
42
|
+
*
|
|
43
|
+
* Returns the session object or null if not authenticated.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getSession(request?: Request): Promise<any>;
|
|
46
|
+
/**
|
|
47
|
+
* Get the current session, throwing if not authenticated.
|
|
48
|
+
* Use in API handlers that require auth.
|
|
49
|
+
*/
|
|
50
|
+
export declare function requireSession(request: Request): Promise<any>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Server-side auth utilities for Better Auth (v4.0)
|
|
4
|
+
*
|
|
5
|
+
* Replaces:
|
|
6
|
+
* - getToken() from next-auth/jwt
|
|
7
|
+
* - getServerSession() from next-auth
|
|
8
|
+
*
|
|
9
|
+
* All server-side auth flows go through the Better Auth instance.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getAuthInstance = getAuthInstance;
|
|
13
|
+
exports.getSession = getSession;
|
|
14
|
+
exports.requireSession = requireSession;
|
|
15
|
+
require("server-only");
|
|
16
|
+
const better_auth_1 = require("../auth/better-auth");
|
|
17
|
+
const idp_client_config_1 = require("../lib/idp-client-config");
|
|
18
|
+
let authInstance = null;
|
|
19
|
+
let authInitPromise = null;
|
|
20
|
+
/**
|
|
21
|
+
* Get the initialized Better Auth instance (singleton).
|
|
22
|
+
*/
|
|
23
|
+
async function getAuthInstance() {
|
|
24
|
+
if (authInstance)
|
|
25
|
+
return authInstance;
|
|
26
|
+
if (!authInitPromise) {
|
|
27
|
+
authInitPromise = (0, idp_client_config_1.getIDPClientConfig)().then(config => {
|
|
28
|
+
authInstance = (0, better_auth_1.createBetterAuthInstance)(config);
|
|
29
|
+
return authInstance;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return authInitPromise;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get the current session from a request.
|
|
36
|
+
* Replaces getToken() and getServerSession().
|
|
37
|
+
*
|
|
38
|
+
* Returns the session object or null if not authenticated.
|
|
39
|
+
*/
|
|
40
|
+
async function getSession(request) {
|
|
41
|
+
const auth = await getAuthInstance();
|
|
42
|
+
if (!request)
|
|
43
|
+
return null;
|
|
44
|
+
try {
|
|
45
|
+
const session = await auth.api.getSession({ headers: request.headers });
|
|
46
|
+
return session;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get the current session, throwing if not authenticated.
|
|
54
|
+
* Use in API handlers that require auth.
|
|
55
|
+
*/
|
|
56
|
+
async function requireSession(request) {
|
|
57
|
+
const session = await getSession(request);
|
|
58
|
+
if (!session) {
|
|
59
|
+
throw new Error('Unauthorized');
|
|
60
|
+
}
|
|
61
|
+
return session;
|
|
62
|
+
}
|
package/dist/stores/authStore.js
CHANGED
|
@@ -49,7 +49,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
49
49
|
exports.initializeAuthStore = exports.useAuthStore = void 0;
|
|
50
50
|
const zustand_1 = require("zustand");
|
|
51
51
|
const middleware_1 = require("zustand/middleware");
|
|
52
|
-
const
|
|
52
|
+
const better_auth_client_1 = require("../client/better-auth-client");
|
|
53
53
|
const session_1 = require("../lib/session");
|
|
54
54
|
const logger_1 = require("../config/logger");
|
|
55
55
|
const signalr_1 = require("@microsoft/signalr");
|
|
@@ -254,18 +254,19 @@ exports.useAuthStore = (0, zustand_1.create)()((0, middleware_1.devtools)((set,
|
|
|
254
254
|
signIn: async (credentials) => {
|
|
255
255
|
set({ isLoading: true, error: null });
|
|
256
256
|
try {
|
|
257
|
-
// Use
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
redirect: false,
|
|
257
|
+
// Use Better Auth signIn
|
|
258
|
+
const result = await better_auth_client_1.authClient.signIn.email({
|
|
259
|
+
email: credentials.email,
|
|
260
|
+
password: credentials.password,
|
|
262
261
|
});
|
|
263
|
-
if (result?.
|
|
262
|
+
if (result?.data) {
|
|
264
263
|
logger_1.authLogger.info('[AuthStore] Sign in successful');
|
|
265
264
|
return true;
|
|
266
265
|
}
|
|
267
266
|
else {
|
|
268
|
-
const errorMessage = result?.error
|
|
267
|
+
const errorMessage = result?.error
|
|
268
|
+
? (typeof result.error === 'object' ? result.error.message : String(result.error))
|
|
269
|
+
: 'Sign in failed';
|
|
269
270
|
set({ error: errorMessage, isLoading: false });
|
|
270
271
|
return false;
|
|
271
272
|
}
|
|
@@ -291,8 +292,8 @@ exports.useAuthStore = (0, zustand_1.create)()((0, middleware_1.devtools)((set,
|
|
|
291
292
|
rolesLastFetch: null,
|
|
292
293
|
});
|
|
293
294
|
try {
|
|
294
|
-
// Use
|
|
295
|
-
await
|
|
295
|
+
// Use Better Auth signOut
|
|
296
|
+
await better_auth_client_1.authClient.signOut();
|
|
296
297
|
logger_1.authLogger.info('[AuthStore] Sign out completed');
|
|
297
298
|
}
|
|
298
299
|
catch (error) {
|
|
@@ -361,9 +362,8 @@ exports.useAuthStore = (0, zustand_1.create)()((0, middleware_1.devtools)((set,
|
|
|
361
362
|
}
|
|
362
363
|
});
|
|
363
364
|
}
|
|
364
|
-
// Step 6: Force
|
|
365
|
-
|
|
366
|
-
await signOut({ redirect: false });
|
|
365
|
+
// Step 6: Force Better Auth signOut (this should clear the session cookie)
|
|
366
|
+
await better_auth_client_1.authClient.signOut();
|
|
367
367
|
logger_1.authLogger.info('[AuthStore] Force logout completed, redirecting to login');
|
|
368
368
|
// Step 7: Longer delay to ensure everything is processed
|
|
369
369
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
@@ -421,9 +421,8 @@ exports.useAuthStore = (0, zustand_1.create)()((0, middleware_1.devtools)((set,
|
|
|
421
421
|
if (token)
|
|
422
422
|
return token;
|
|
423
423
|
try {
|
|
424
|
-
const { getSession } = await Promise.resolve().then(() => __importStar(require('next-auth/react')));
|
|
425
424
|
for (let attempt = 1; attempt <= 3 && !token; attempt++) {
|
|
426
|
-
const s = await getSession();
|
|
425
|
+
const { data: s } = await better_auth_client_1.authClient.getSession();
|
|
427
426
|
token = s?.sessionToken;
|
|
428
427
|
if (!token) {
|
|
429
428
|
await new Promise(r => setTimeout(r, 150));
|
|
@@ -431,7 +430,7 @@ exports.useAuthStore = (0, zustand_1.create)()((0, middleware_1.devtools)((set,
|
|
|
431
430
|
}
|
|
432
431
|
}
|
|
433
432
|
catch {
|
|
434
|
-
logger_1.authLogger.warn('[AuthStore] Failed to resolve session token from
|
|
433
|
+
logger_1.authLogger.warn('[AuthStore] Failed to resolve session token from Better Auth during refresh');
|
|
435
434
|
}
|
|
436
435
|
return token;
|
|
437
436
|
};
|
|
@@ -504,15 +503,12 @@ exports.useAuthStore = (0, zustand_1.create)()((0, middleware_1.devtools)((set,
|
|
|
504
503
|
logger_1.authLogger.info('[AuthStore] Starting session rehydration after token refresh');
|
|
505
504
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
506
505
|
try {
|
|
507
|
-
// Force
|
|
508
|
-
// This triggers the JWT callback which reads fresh data from Redis
|
|
509
|
-
const { getSession } = await Promise.resolve().then(() => __importStar(require('next-auth/react')));
|
|
506
|
+
// Force Better Auth to reload the session
|
|
510
507
|
logger_1.authLogger.debug(`[AuthStore] Rehydration attempt ${attempt}/${maxRetries}`);
|
|
511
|
-
// Force session refresh
|
|
512
|
-
|
|
513
|
-
const freshSession = await getSession();
|
|
508
|
+
// Force session refresh via Better Auth
|
|
509
|
+
const { data: freshSession } = await better_auth_client_1.authClient.getSession();
|
|
514
510
|
if (!freshSession) {
|
|
515
|
-
throw new Error('No session returned from
|
|
511
|
+
throw new Error('No session returned from Better Auth after refresh');
|
|
516
512
|
}
|
|
517
513
|
if (!freshSession.accessToken) {
|
|
518
514
|
throw new Error('Fresh session missing access token');
|
package/dist/utils/logout.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.logout = logout;
|
|
12
|
-
const
|
|
12
|
+
const better_auth_client_1 = require("../client/better-auth-client");
|
|
13
13
|
/**
|
|
14
14
|
* Sign out the current user and redirect to login
|
|
15
15
|
*
|
|
@@ -17,10 +17,10 @@ const react_1 = require("next-auth/react");
|
|
|
17
17
|
*/
|
|
18
18
|
async function logout(redirectUrl = '/account-auth/login') {
|
|
19
19
|
try {
|
|
20
|
-
await
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
20
|
+
await better_auth_client_1.authClient.signOut();
|
|
21
|
+
if (typeof window !== 'undefined') {
|
|
22
|
+
window.location.href = redirectUrl;
|
|
23
|
+
}
|
|
24
24
|
}
|
|
25
25
|
catch (error) {
|
|
26
26
|
console.error('Logout error:', error);
|