@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,155 +1,157 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import React, { useState, useEffect } from "react";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Refresh Token Test Page
|
|
7
|
-
*
|
|
8
|
-
* Debug page for testing OAuth refresh token flow.
|
|
9
|
-
* Shows current session state, allows manual refresh trigger,
|
|
10
|
-
* and can force-expire tokens for testing.
|
|
11
|
-
*
|
|
12
|
-
* Usage:
|
|
13
|
-
* ```typescript
|
|
14
|
-
* // app/test-env/refresh-token/page.tsx
|
|
15
|
-
* export { RefreshTokenPage as default } from '@payez/next-mvp/pages/test-env';
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
export function RefreshTokenPage() {
|
|
19
|
-
const { data: session
|
|
20
|
-
|
|
21
|
-
const
|
|
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
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
setResult({
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
<div>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
disabled
|
|
116
|
-
|
|
117
|
-
{loading
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
disabled
|
|
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
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
import React, { useState, useEffect } from "react";
|
|
3
|
+
import { authClient } from '../../client/better-auth-client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Refresh Token Test Page
|
|
7
|
+
*
|
|
8
|
+
* Debug page for testing OAuth refresh token flow.
|
|
9
|
+
* Shows current session state, allows manual refresh trigger,
|
|
10
|
+
* and can force-expire tokens for testing.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* // app/test-env/refresh-token/page.tsx
|
|
15
|
+
* export { RefreshTokenPage as default } from '@payez/next-mvp/pages/test-env';
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function RefreshTokenPage() {
|
|
19
|
+
const { data: session } = authClient.useSession();
|
|
20
|
+
// TODO: Better Auth session refresh
|
|
21
|
+
const update = async () => { /* no-op: Better Auth handles session refresh internally */ };
|
|
22
|
+
const [result, setResult] = useState<any>(null);
|
|
23
|
+
const [loading, setLoading] = useState(false);
|
|
24
|
+
const [sessionDetails, setSessionDetails] = useState<any>(null);
|
|
25
|
+
|
|
26
|
+
// Fetch detailed session info on mount
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
async function fetchSessionDetails() {
|
|
29
|
+
try {
|
|
30
|
+
const res = await fetch("/api/auth/session", { credentials: "include" });
|
|
31
|
+
const data = await res.json();
|
|
32
|
+
setSessionDetails(data);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
console.error("Failed to fetch session details", e);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
fetchSessionDetails();
|
|
38
|
+
}, [result]); // Refetch after refresh
|
|
39
|
+
|
|
40
|
+
async function handleRefresh() {
|
|
41
|
+
setLoading(true);
|
|
42
|
+
setResult(null);
|
|
43
|
+
try {
|
|
44
|
+
const res = await fetch("/api/auth/refresh", {
|
|
45
|
+
method: "POST",
|
|
46
|
+
headers: { "Content-Type": "application/json" },
|
|
47
|
+
credentials: "include",
|
|
48
|
+
});
|
|
49
|
+
const data = await res.json();
|
|
50
|
+
setResult({ status: res.status, ...data });
|
|
51
|
+
// Update NextAuth session
|
|
52
|
+
await update();
|
|
53
|
+
} catch (e: any) {
|
|
54
|
+
setResult({ error: e.message });
|
|
55
|
+
} finally {
|
|
56
|
+
setLoading(false);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function handleForceExpire() {
|
|
61
|
+
setLoading(true);
|
|
62
|
+
setResult(null);
|
|
63
|
+
try {
|
|
64
|
+
const res = await fetch("/api/test/force-expire", {
|
|
65
|
+
method: "POST",
|
|
66
|
+
credentials: "include",
|
|
67
|
+
});
|
|
68
|
+
const data = await res.json();
|
|
69
|
+
setResult({ action: "force_expire", status: res.status, ...data });
|
|
70
|
+
} catch (e: any) {
|
|
71
|
+
setResult({ error: e.message });
|
|
72
|
+
} finally {
|
|
73
|
+
setLoading(false);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const formatExpiry = (exp: number | string | undefined) => {
|
|
78
|
+
if (!exp) return "N/A";
|
|
79
|
+
const date = new Date(typeof exp === "string" ? exp : exp);
|
|
80
|
+
const now = new Date();
|
|
81
|
+
const diffMs = date.getTime() - now.getTime();
|
|
82
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
83
|
+
const diffSecs = Math.floor((diffMs % 60000) / 1000);
|
|
84
|
+
return `${date.toLocaleTimeString()} (${diffMins}m ${diffSecs}s remaining)`;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<div className="p-8 max-w-2xl mx-auto bg-gray-900 min-h-screen text-white">
|
|
89
|
+
<h1 className="text-2xl font-bold mb-4">Refresh Token Test</h1>
|
|
90
|
+
|
|
91
|
+
{/* Session Info */}
|
|
92
|
+
<div className="mb-6 rounded border border-blue-500 bg-blue-900/30 p-4">
|
|
93
|
+
<h2 className="font-semibold mb-2 text-blue-300">Current Session</h2>
|
|
94
|
+
<div className="text-sm space-y-1 font-mono">
|
|
95
|
+
<div><span className="text-gray-400">User:</span> {session?.user?.email || "Not logged in"}</div>
|
|
96
|
+
<div><span className="text-gray-400">2FA Complete:</span> {String((session?.user as any)?.twoFactorSessionVerified ?? "unknown")}</div>
|
|
97
|
+
<div>
|
|
98
|
+
<span className="text-gray-400">Access Token:</span>{" "}
|
|
99
|
+
{sessionDetails?.accessToken ? `${sessionDetails.accessToken.substring(0, 40)}...` : "N/A"}
|
|
100
|
+
</div>
|
|
101
|
+
<div>
|
|
102
|
+
<span className="text-gray-400">Refresh Token:</span>{" "}
|
|
103
|
+
{sessionDetails?.refreshToken ? `${sessionDetails.refreshToken.substring(0, 40)}...` : "N/A"}
|
|
104
|
+
</div>
|
|
105
|
+
<div>
|
|
106
|
+
<span className="text-gray-400">Access Expires:</span>{" "}
|
|
107
|
+
{formatExpiry(sessionDetails?.accessTokenExpires)}
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
{/* Actions */}
|
|
113
|
+
<div className="flex gap-2 mb-4">
|
|
114
|
+
<button
|
|
115
|
+
className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded disabled:opacity-50"
|
|
116
|
+
onClick={handleRefresh}
|
|
117
|
+
disabled={loading}
|
|
118
|
+
>
|
|
119
|
+
{loading ? "Refreshing..." : "Test Refresh Token"}
|
|
120
|
+
</button>
|
|
121
|
+
<button
|
|
122
|
+
className="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded disabled:opacity-50"
|
|
123
|
+
onClick={handleForceExpire}
|
|
124
|
+
disabled={loading}
|
|
125
|
+
>
|
|
126
|
+
Force Expire Token
|
|
127
|
+
</button>
|
|
128
|
+
<button
|
|
129
|
+
className="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded"
|
|
130
|
+
onClick={() => window.location.reload()}
|
|
131
|
+
>
|
|
132
|
+
Reload Page
|
|
133
|
+
</button>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
{/* Result */}
|
|
137
|
+
{result && (
|
|
138
|
+
<div className="rounded border border-gray-600 bg-gray-800 p-4">
|
|
139
|
+
<h3 className="font-semibold mb-2 text-gray-300">Result:</h3>
|
|
140
|
+
<pre className="text-xs overflow-x-auto whitespace-pre-wrap text-green-400">
|
|
141
|
+
{JSON.stringify(result, null, 2)}
|
|
142
|
+
</pre>
|
|
143
|
+
</div>
|
|
144
|
+
)}
|
|
145
|
+
|
|
146
|
+
{/* Raw Session Details */}
|
|
147
|
+
<details className="mt-4">
|
|
148
|
+
<summary className="cursor-pointer text-gray-400 hover:text-white">Raw Session Details</summary>
|
|
149
|
+
<pre className="mt-2 text-xs bg-gray-800 p-2 rounded overflow-x-auto text-gray-300">
|
|
150
|
+
{JSON.stringify(sessionDetails, null, 2)}
|
|
151
|
+
</pre>
|
|
152
|
+
</details>
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export default RefreshTokenPage;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { authClient } from '../../client/better-auth-client';
|
|
4
4
|
import { useState, useEffect } from 'react';
|
|
5
5
|
import Link from 'next/link';
|
|
6
6
|
|
|
@@ -16,7 +16,9 @@ import Link from 'next/link';
|
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
18
|
export function TestEnvPage() {
|
|
19
|
-
const { data:
|
|
19
|
+
const { data: sessionData, isPending } = authClient.useSession();
|
|
20
|
+
const session = sessionData;
|
|
21
|
+
const status = isPending ? 'loading' : session ? 'authenticated' : 'unauthenticated';
|
|
20
22
|
const [isDarkMode, setIsDarkMode] = useState(false);
|
|
21
23
|
|
|
22
24
|
useEffect(() => {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
import React, { useState, useEffect, useRef } from 'react';
|
|
34
34
|
import { useRouter, useSearchParams } from 'next/navigation';
|
|
35
|
-
import {
|
|
35
|
+
import { authClient } from '../../client/better-auth-client';
|
|
36
36
|
import { Suspense } from 'react';
|
|
37
37
|
import { useColors } from '../../theme/useTheme';
|
|
38
38
|
|
|
@@ -54,7 +54,11 @@ function VerifyCodeForm() {
|
|
|
54
54
|
const searchParams = useSearchParams();
|
|
55
55
|
const callbackUrl = searchParams?.get('callbackUrl') || '/dashboard';
|
|
56
56
|
|
|
57
|
-
const { data:
|
|
57
|
+
const { data: sessionData, isPending } = authClient.useSession();
|
|
58
|
+
const session = sessionData;
|
|
59
|
+
const status = isPending ? 'loading' : session ? 'authenticated' : 'unauthenticated';
|
|
60
|
+
// TODO: Better Auth session refresh
|
|
61
|
+
const updateSession = async () => { return session; };
|
|
58
62
|
const colors = useColors();
|
|
59
63
|
|
|
60
64
|
// Method selection
|
|
@@ -146,7 +150,7 @@ function VerifyCodeForm() {
|
|
|
146
150
|
// Session expired - redirect to login
|
|
147
151
|
setError('Your session has expired. Redirecting to login...');
|
|
148
152
|
setTimeout(async () => {
|
|
149
|
-
await signOut(
|
|
153
|
+
await authClient.signOut();
|
|
150
154
|
const safeCallback = callbackUrl.startsWith('/account-auth/') ? '/dashboard' : callbackUrl;
|
|
151
155
|
router.push(`/account-auth/login?callbackUrl=${encodeURIComponent(safeCallback)}`);
|
|
152
156
|
}, 1200);
|
|
@@ -197,7 +201,7 @@ function VerifyCodeForm() {
|
|
|
197
201
|
if (data.valid === false || data.mfaExpired === true) {
|
|
198
202
|
setError('Your session has expired. Redirecting to login...');
|
|
199
203
|
setTimeout(async () => {
|
|
200
|
-
await signOut(
|
|
204
|
+
await authClient.signOut();
|
|
201
205
|
if (typeof window !== 'undefined') {
|
|
202
206
|
sessionStorage.removeItem(VERIFY_IN_PROGRESS_KEY);
|
|
203
207
|
}
|
|
@@ -243,7 +247,7 @@ function VerifyCodeForm() {
|
|
|
243
247
|
);
|
|
244
248
|
|
|
245
249
|
setTimeout(async () => {
|
|
246
|
-
await signOut(
|
|
250
|
+
await authClient.signOut();
|
|
247
251
|
if (typeof window !== 'undefined') {
|
|
248
252
|
sessionStorage.removeItem(VERIFY_IN_PROGRESS_KEY);
|
|
249
253
|
}
|
|
@@ -318,7 +322,7 @@ function VerifyCodeForm() {
|
|
|
318
322
|
);
|
|
319
323
|
|
|
320
324
|
setTimeout(async () => {
|
|
321
|
-
await signOut(
|
|
325
|
+
await authClient.signOut();
|
|
322
326
|
if (typeof window !== 'undefined') {
|
|
323
327
|
sessionStorage.removeItem(VERIFY_IN_PROGRESS_KEY);
|
|
324
328
|
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { NextRequest, NextResponse } from 'next/server';
|
|
18
|
-
import {
|
|
18
|
+
import { getSession } from '../../server/auth';
|
|
19
19
|
import { deleteSession } from '../../lib/session-store';
|
|
20
20
|
import {
|
|
21
21
|
getSessionCookieName,
|
|
@@ -23,39 +23,22 @@ import {
|
|
|
23
23
|
getCsrfCookieName,
|
|
24
24
|
getSecureCsrfCookieName,
|
|
25
25
|
getCallbackUrlCookieName,
|
|
26
|
-
getJwtCookieName
|
|
27
26
|
} from '../../lib/app-slug';
|
|
28
|
-
import { getIDPClientConfig } from '../../lib/idp-client-config';
|
|
29
27
|
import { siteEvents, getClientIp } from '../../lib/site-logger';
|
|
30
28
|
|
|
31
|
-
async function getConfig() {
|
|
32
|
-
const idpConfig = await getIDPClientConfig();
|
|
33
|
-
const idpBaseUrl = process.env.IDP_URL;
|
|
34
|
-
if (!idpBaseUrl) {
|
|
35
|
-
throw new Error('[IDP_URL] FATAL: IDP_URL environment variable is REQUIRED.');
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
nextAuthSecret: idpConfig.nextAuthSecret || '',
|
|
39
|
-
idpBaseUrl,
|
|
40
|
-
clientId: process.env.CLIENT_ID || process.env.NEXT_PUBLIC_IDP_CLIENT_ID || '',
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
29
|
/**
|
|
45
30
|
* POST /api/auth/logout - Sign out and clean up session
|
|
46
31
|
*
|
|
47
32
|
* Performs complete logout:
|
|
48
33
|
* 1. Revokes tokens at IDP (if refresh token available)
|
|
49
34
|
* 2. Deletes session from store
|
|
50
|
-
* 3. Clears
|
|
35
|
+
* 3. Clears session cookies
|
|
51
36
|
*/
|
|
52
37
|
export async function POST(req: NextRequest) {
|
|
53
|
-
const { nextAuthSecret, idpBaseUrl, clientId } = await getConfig();
|
|
54
|
-
|
|
55
38
|
try {
|
|
56
|
-
const
|
|
39
|
+
const session = await getSession(req);
|
|
57
40
|
|
|
58
|
-
if (!
|
|
41
|
+
if (!session) {
|
|
59
42
|
// Already logged out
|
|
60
43
|
return NextResponse.json({
|
|
61
44
|
success: true,
|
|
@@ -63,8 +46,7 @@ export async function POST(req: NextRequest) {
|
|
|
63
46
|
});
|
|
64
47
|
}
|
|
65
48
|
|
|
66
|
-
|
|
67
|
-
const sessionId = (token as any).sessionToken || (token as any).redisSessionId;
|
|
49
|
+
const sessionId = session.session?.token;
|
|
68
50
|
|
|
69
51
|
// Delete session from store (this also removes the refresh token)
|
|
70
52
|
if (sessionId) {
|
|
@@ -77,7 +59,7 @@ export async function POST(req: NextRequest) {
|
|
|
77
59
|
}
|
|
78
60
|
|
|
79
61
|
// Log logout event (fire-and-forget)
|
|
80
|
-
const userId =
|
|
62
|
+
const userId = session.user?.id;
|
|
81
63
|
if (userId) {
|
|
82
64
|
siteEvents.logout({
|
|
83
65
|
user_id: userId,
|
|
@@ -89,7 +71,7 @@ export async function POST(req: NextRequest) {
|
|
|
89
71
|
});
|
|
90
72
|
}
|
|
91
73
|
|
|
92
|
-
// Build response that clears
|
|
74
|
+
// Build response that clears session cookies
|
|
93
75
|
const response = NextResponse.json({
|
|
94
76
|
success: true,
|
|
95
77
|
message: 'Logged out successfully'
|
|
@@ -1,71 +1,45 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ready-to-Use
|
|
3
|
-
*
|
|
4
|
-
* Provides a pre-configured
|
|
5
|
-
* loaded from IDP at startup
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return cachedHandler;
|
|
47
|
-
} finally {
|
|
48
|
-
handlerPromise = null;
|
|
49
|
-
}
|
|
50
|
-
})();
|
|
51
|
-
|
|
52
|
-
return handlerPromise;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* GET handler for NextAuth
|
|
57
|
-
* Uses async factory to get dynamic providers from IDP
|
|
58
|
-
*/
|
|
59
|
-
export async function GET(request: Request, context: any) {
|
|
60
|
-
const handler = await getHandler();
|
|
61
|
-
return handler(request, context);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* POST handler for NextAuth
|
|
66
|
-
* Uses async factory to get dynamic providers from IDP
|
|
67
|
-
*/
|
|
68
|
-
export async function POST(request: Request, context: any) {
|
|
69
|
-
const handler = await getHandler();
|
|
70
|
-
return handler(request, context);
|
|
71
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Ready-to-Use Auth Route Handler (Better Auth)
|
|
3
|
+
*
|
|
4
|
+
* Provides a pre-configured Better Auth handler that uses dynamic OAuth providers
|
|
5
|
+
* loaded from IDP at startup.
|
|
6
|
+
*
|
|
7
|
+
* Replaces the former NextAuth handler. The file name is kept as nextauth.ts
|
|
8
|
+
* to avoid breaking re-exports in routes/auth/index.ts.
|
|
9
|
+
*
|
|
10
|
+
* @version 4.0.0 - Better Auth migration
|
|
11
|
+
* @since better-auth-4.0
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { getBetterAuthHandler } from '../../auth/better-auth';
|
|
15
|
+
import { NextResponse } from 'next/server';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* GET handler for auth routes
|
|
19
|
+
* Delegates to Better Auth instance.
|
|
20
|
+
*/
|
|
21
|
+
export async function GET(request: Request) {
|
|
22
|
+
const handler = await getBetterAuthHandler();
|
|
23
|
+
if (!handler) {
|
|
24
|
+
return NextResponse.json(
|
|
25
|
+
{ error: 'Auth handler not available' },
|
|
26
|
+
{ status: 503 }
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
return handler.GET(request);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* POST handler for auth routes
|
|
34
|
+
* Delegates to Better Auth instance.
|
|
35
|
+
*/
|
|
36
|
+
export async function POST(request: Request) {
|
|
37
|
+
const handler = await getBetterAuthHandler();
|
|
38
|
+
if (!handler) {
|
|
39
|
+
return NextResponse.json(
|
|
40
|
+
{ error: 'Auth handler not available' },
|
|
41
|
+
{ status: 503 }
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return handler.POST(request);
|
|
45
|
+
}
|