@auth-gate/nextjs 0.1.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/index.cjs +639 -0
- package/dist/index.d.cts +224 -0
- package/dist/index.d.ts +224 -0
- package/dist/index.mjs +608 -0
- package/package.json +36 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { createAuthGateClient } from "@auth-gate/core";
|
|
3
|
+
|
|
4
|
+
// src/session.ts
|
|
5
|
+
import { cookies } from "next/headers";
|
|
6
|
+
function createSessionHelpers(client) {
|
|
7
|
+
async function getSession() {
|
|
8
|
+
const cookieStore = await cookies();
|
|
9
|
+
const cookie = cookieStore.get(client.cookieName);
|
|
10
|
+
if (!cookie) return null;
|
|
11
|
+
return client.decryptSession(cookie.value);
|
|
12
|
+
}
|
|
13
|
+
async function setSession(user) {
|
|
14
|
+
const cookieStore = await cookies();
|
|
15
|
+
const encrypted = await client.encryptSession(user);
|
|
16
|
+
const options = client.getSessionCookieOptions();
|
|
17
|
+
cookieStore.set(client.cookieName, encrypted, options);
|
|
18
|
+
}
|
|
19
|
+
async function clearSession() {
|
|
20
|
+
const cookieStore = await cookies();
|
|
21
|
+
cookieStore.set(client.cookieName, "", {
|
|
22
|
+
httpOnly: true,
|
|
23
|
+
secure: process.env.NODE_ENV === "production",
|
|
24
|
+
sameSite: "lax",
|
|
25
|
+
maxAge: 0,
|
|
26
|
+
path: "/"
|
|
27
|
+
});
|
|
28
|
+
cookieStore.set(client.refreshTokenCookieName, "", {
|
|
29
|
+
httpOnly: true,
|
|
30
|
+
secure: process.env.NODE_ENV === "production",
|
|
31
|
+
sameSite: "lax",
|
|
32
|
+
maxAge: 0,
|
|
33
|
+
path: "/"
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return { getSession, setSession, clearSession };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/handlers.ts
|
|
40
|
+
import { cookies as cookies2 } from "next/headers";
|
|
41
|
+
import { NextResponse } from "next/server";
|
|
42
|
+
import { SUPPORTED_PROVIDERS } from "@auth-gate/core";
|
|
43
|
+
function createHandlers(client, appUrl) {
|
|
44
|
+
const { getSession, setSession, clearSession } = createSessionHelpers(client);
|
|
45
|
+
async function providerLogin(_request, { params }) {
|
|
46
|
+
const { provider } = await params;
|
|
47
|
+
if (!SUPPORTED_PROVIDERS.includes(provider)) {
|
|
48
|
+
return NextResponse.json(
|
|
49
|
+
{ error: "Unsupported provider" },
|
|
50
|
+
{ status: 400 }
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
const { state, nonce } = await client.createState();
|
|
54
|
+
const cookieStore = await cookies2();
|
|
55
|
+
cookieStore.set(client.nonceCookieName, nonce, client.getNonceCookieOptions());
|
|
56
|
+
const callbackUrl = `${appUrl}${client.callbackPath}`;
|
|
57
|
+
const authUrl = client.getOAuthUrl(provider, callbackUrl);
|
|
58
|
+
const url = new URL(authUrl);
|
|
59
|
+
url.searchParams.set("state", state);
|
|
60
|
+
return NextResponse.redirect(url);
|
|
61
|
+
}
|
|
62
|
+
async function callback(request) {
|
|
63
|
+
var _a;
|
|
64
|
+
const token = request.nextUrl.searchParams.get("token");
|
|
65
|
+
const state = request.nextUrl.searchParams.get("state");
|
|
66
|
+
const mfaChallenge = request.nextUrl.searchParams.get("mfa_challenge");
|
|
67
|
+
const mfaMethods = request.nextUrl.searchParams.get("mfa_methods");
|
|
68
|
+
const mfaSetupRequired = request.nextUrl.searchParams.get("mfa_setup_required");
|
|
69
|
+
const refreshToken = request.nextUrl.searchParams.get("refresh_token");
|
|
70
|
+
if (mfaChallenge) {
|
|
71
|
+
const mfaUrl = new URL("/mfa-verify", request.url);
|
|
72
|
+
mfaUrl.searchParams.set("mfa_challenge", mfaChallenge);
|
|
73
|
+
if (mfaMethods) mfaUrl.searchParams.set("mfa_methods", mfaMethods);
|
|
74
|
+
return NextResponse.redirect(mfaUrl);
|
|
75
|
+
}
|
|
76
|
+
if (!token) {
|
|
77
|
+
return NextResponse.redirect(
|
|
78
|
+
new URL("/login?error=missing_token", request.url)
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (state) {
|
|
82
|
+
const cookieStore = await cookies2();
|
|
83
|
+
const nonce = (_a = cookieStore.get(client.nonceCookieName)) == null ? void 0 : _a.value;
|
|
84
|
+
cookieStore.set(client.nonceCookieName, "", {
|
|
85
|
+
httpOnly: true,
|
|
86
|
+
secure: process.env.NODE_ENV === "production",
|
|
87
|
+
sameSite: "lax",
|
|
88
|
+
maxAge: 0,
|
|
89
|
+
path: "/"
|
|
90
|
+
});
|
|
91
|
+
if (!nonce || !await client.verifyState(state, nonce)) {
|
|
92
|
+
return NextResponse.redirect(
|
|
93
|
+
new URL("/login?error=invalid_state", request.url)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const result = await client.verifyToken(token);
|
|
98
|
+
if (!result.valid || !result.user) {
|
|
99
|
+
return NextResponse.redirect(
|
|
100
|
+
new URL("/login?error=invalid_token", request.url)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
await setSession(result.user);
|
|
104
|
+
if (refreshToken) {
|
|
105
|
+
const cookieStore = await cookies2();
|
|
106
|
+
cookieStore.set(client.refreshTokenCookieName, refreshToken, {
|
|
107
|
+
httpOnly: true,
|
|
108
|
+
secure: process.env.NODE_ENV === "production",
|
|
109
|
+
sameSite: "lax",
|
|
110
|
+
maxAge: client.sessionMaxAge,
|
|
111
|
+
path: "/"
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if (mfaSetupRequired) {
|
|
115
|
+
return NextResponse.redirect(new URL("/mfa-setup", request.url));
|
|
116
|
+
}
|
|
117
|
+
return NextResponse.redirect(new URL("/dashboard", request.url));
|
|
118
|
+
}
|
|
119
|
+
async function emailSignup(request) {
|
|
120
|
+
const body = await request.json();
|
|
121
|
+
const { email, password, name } = body;
|
|
122
|
+
if (!email || !password) {
|
|
123
|
+
return NextResponse.json(
|
|
124
|
+
{ error: "Missing email or password" },
|
|
125
|
+
{ status: 400 }
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const response = await client.emailSignup({
|
|
129
|
+
email,
|
|
130
|
+
password,
|
|
131
|
+
name,
|
|
132
|
+
callbackUrl: `${appUrl}${client.callbackPath}`
|
|
133
|
+
});
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
136
|
+
return NextResponse.json(error, { status: response.status });
|
|
137
|
+
}
|
|
138
|
+
const data = await response.json().catch(() => ({ error: "Request failed" }));
|
|
139
|
+
const verified = await client.verifyToken(data.token);
|
|
140
|
+
if (!verified.valid || !verified.user) {
|
|
141
|
+
return NextResponse.json(
|
|
142
|
+
{ error: "Token verification failed" },
|
|
143
|
+
{ status: 401 }
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
await setSession(verified.user);
|
|
147
|
+
if (data.refresh_token) {
|
|
148
|
+
const cookieStore = await cookies2();
|
|
149
|
+
cookieStore.set(client.refreshTokenCookieName, data.refresh_token, {
|
|
150
|
+
httpOnly: true,
|
|
151
|
+
secure: process.env.NODE_ENV === "production",
|
|
152
|
+
sameSite: "lax",
|
|
153
|
+
maxAge: client.sessionMaxAge,
|
|
154
|
+
path: "/"
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return NextResponse.json({ success: true, redirect: "/dashboard" });
|
|
158
|
+
}
|
|
159
|
+
async function emailSignin(request) {
|
|
160
|
+
const body = await request.json();
|
|
161
|
+
const { email, password } = body;
|
|
162
|
+
if (!email || !password) {
|
|
163
|
+
return NextResponse.json(
|
|
164
|
+
{ error: "Missing email or password" },
|
|
165
|
+
{ status: 400 }
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
const response = await client.emailSignin({
|
|
169
|
+
email,
|
|
170
|
+
password,
|
|
171
|
+
callbackUrl: `${appUrl}${client.callbackPath}`
|
|
172
|
+
});
|
|
173
|
+
if (!response.ok) {
|
|
174
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
175
|
+
return NextResponse.json(error, { status: response.status });
|
|
176
|
+
}
|
|
177
|
+
const data = await response.json().catch(() => ({ error: "Request failed" }));
|
|
178
|
+
if (data.mfa_required) {
|
|
179
|
+
return NextResponse.json({
|
|
180
|
+
mfa_required: true,
|
|
181
|
+
mfa_challenge: data.mfa_challenge,
|
|
182
|
+
mfa_methods: data.mfa_methods
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
const verified = await client.verifyToken(data.token);
|
|
186
|
+
if (!verified.valid || !verified.user) {
|
|
187
|
+
return NextResponse.json(
|
|
188
|
+
{ error: "Token verification failed" },
|
|
189
|
+
{ status: 401 }
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
await setSession(verified.user);
|
|
193
|
+
if (data.refresh_token) {
|
|
194
|
+
const cookieStore = await cookies2();
|
|
195
|
+
cookieStore.set(client.refreshTokenCookieName, data.refresh_token, {
|
|
196
|
+
httpOnly: true,
|
|
197
|
+
secure: process.env.NODE_ENV === "production",
|
|
198
|
+
sameSite: "lax",
|
|
199
|
+
maxAge: client.sessionMaxAge,
|
|
200
|
+
path: "/"
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return NextResponse.json({
|
|
204
|
+
success: true,
|
|
205
|
+
redirect: data.mfa_setup_required ? "/mfa-setup" : "/dashboard"
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
async function emailForgotPassword(request) {
|
|
209
|
+
const body = await request.json();
|
|
210
|
+
const { email } = body;
|
|
211
|
+
if (!email) {
|
|
212
|
+
return NextResponse.json(
|
|
213
|
+
{ error: "Missing email" },
|
|
214
|
+
{ status: 400 }
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
const response = await client.emailForgotPassword({
|
|
218
|
+
email,
|
|
219
|
+
callbackUrl: `${appUrl}/reset-password`
|
|
220
|
+
});
|
|
221
|
+
if (!response.ok) {
|
|
222
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
223
|
+
return NextResponse.json(error, { status: response.status });
|
|
224
|
+
}
|
|
225
|
+
return NextResponse.json({ success: true });
|
|
226
|
+
}
|
|
227
|
+
async function emailResetPassword(request) {
|
|
228
|
+
const body = await request.json();
|
|
229
|
+
const { token, password } = body;
|
|
230
|
+
if (!token || !password) {
|
|
231
|
+
return NextResponse.json(
|
|
232
|
+
{ error: "Missing token or password" },
|
|
233
|
+
{ status: 400 }
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
const response = await client.emailResetPassword({ token, password });
|
|
237
|
+
if (!response.ok) {
|
|
238
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
239
|
+
return NextResponse.json(error, { status: response.status });
|
|
240
|
+
}
|
|
241
|
+
const data = await response.json().catch(() => ({ error: "Request failed" }));
|
|
242
|
+
if (data.token) {
|
|
243
|
+
const verified = await client.verifyToken(data.token);
|
|
244
|
+
if (verified.valid && verified.user) {
|
|
245
|
+
await setSession(verified.user);
|
|
246
|
+
return NextResponse.json({
|
|
247
|
+
success: true,
|
|
248
|
+
redirect: "/dashboard"
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return NextResponse.json({ success: true, redirect: "/login" });
|
|
253
|
+
}
|
|
254
|
+
async function magicLinkSend(request) {
|
|
255
|
+
const body = await request.json();
|
|
256
|
+
const { email } = body;
|
|
257
|
+
if (!email) {
|
|
258
|
+
return NextResponse.json(
|
|
259
|
+
{ error: "Missing email" },
|
|
260
|
+
{ status: 400 }
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
const response = await client.magicLinkSend({
|
|
264
|
+
email,
|
|
265
|
+
callbackUrl: `${appUrl}${client.callbackPath}`
|
|
266
|
+
});
|
|
267
|
+
if (!response.ok) {
|
|
268
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
269
|
+
return NextResponse.json(error, { status: response.status });
|
|
270
|
+
}
|
|
271
|
+
return NextResponse.json({ success: true });
|
|
272
|
+
}
|
|
273
|
+
async function emailVerifyCode(request) {
|
|
274
|
+
const body = await request.json();
|
|
275
|
+
const { email, code } = body;
|
|
276
|
+
if (!email || !code) {
|
|
277
|
+
return NextResponse.json(
|
|
278
|
+
{ error: "Missing email or code" },
|
|
279
|
+
{ status: 400 }
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
const response = await client.emailVerifyCode({ email, code });
|
|
283
|
+
if (!response.ok) {
|
|
284
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
285
|
+
return NextResponse.json(error, { status: response.status });
|
|
286
|
+
}
|
|
287
|
+
return NextResponse.json({ success: true, email_verified: true });
|
|
288
|
+
}
|
|
289
|
+
async function smsSendCode(request) {
|
|
290
|
+
const body = await request.json();
|
|
291
|
+
const { phone } = body;
|
|
292
|
+
if (!phone) {
|
|
293
|
+
return NextResponse.json(
|
|
294
|
+
{ error: "Missing phone number" },
|
|
295
|
+
{ status: 400 }
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
const response = await client.smsSendCode({
|
|
299
|
+
phone,
|
|
300
|
+
callbackUrl: `${appUrl}${client.callbackPath}`
|
|
301
|
+
});
|
|
302
|
+
if (!response.ok) {
|
|
303
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
304
|
+
return NextResponse.json(error, { status: response.status });
|
|
305
|
+
}
|
|
306
|
+
return NextResponse.json({ success: true });
|
|
307
|
+
}
|
|
308
|
+
async function smsVerifyCode(request) {
|
|
309
|
+
const body = await request.json();
|
|
310
|
+
const { phone, code } = body;
|
|
311
|
+
if (!phone || !code) {
|
|
312
|
+
return NextResponse.json(
|
|
313
|
+
{ error: "Missing phone or code" },
|
|
314
|
+
{ status: 400 }
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
const response = await client.smsVerifyCode({
|
|
318
|
+
phone,
|
|
319
|
+
code,
|
|
320
|
+
callbackUrl: `${appUrl}${client.callbackPath}`
|
|
321
|
+
});
|
|
322
|
+
if (!response.ok) {
|
|
323
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
324
|
+
return NextResponse.json(error, { status: response.status });
|
|
325
|
+
}
|
|
326
|
+
const data = await response.json().catch(() => ({ error: "Request failed" }));
|
|
327
|
+
const verified = await client.verifyToken(data.token);
|
|
328
|
+
if (!verified.valid || !verified.user) {
|
|
329
|
+
return NextResponse.json(
|
|
330
|
+
{ error: "Token verification failed" },
|
|
331
|
+
{ status: 401 }
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
await setSession(verified.user);
|
|
335
|
+
return NextResponse.json({ success: true, redirect: "/dashboard" });
|
|
336
|
+
}
|
|
337
|
+
async function mfaVerify(request) {
|
|
338
|
+
const body = await request.json();
|
|
339
|
+
const { challenge, code, method } = body;
|
|
340
|
+
if (!challenge || !code || !method) {
|
|
341
|
+
return NextResponse.json(
|
|
342
|
+
{ error: "Missing challenge, code, or method" },
|
|
343
|
+
{ status: 400 }
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
const response = await client.mfaVerify({ challenge, code, method });
|
|
347
|
+
if (!response.ok) {
|
|
348
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
349
|
+
return NextResponse.json(error, { status: response.status });
|
|
350
|
+
}
|
|
351
|
+
const data = await response.json();
|
|
352
|
+
const verified = await client.verifyToken(data.token);
|
|
353
|
+
if (!verified.valid || !verified.user) {
|
|
354
|
+
return NextResponse.json(
|
|
355
|
+
{ error: "Token verification failed" },
|
|
356
|
+
{ status: 401 }
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
await setSession(verified.user);
|
|
360
|
+
if (data.refresh_token) {
|
|
361
|
+
const cookieStore = await cookies2();
|
|
362
|
+
cookieStore.set(client.refreshTokenCookieName, data.refresh_token, {
|
|
363
|
+
httpOnly: true,
|
|
364
|
+
secure: process.env.NODE_ENV === "production",
|
|
365
|
+
sameSite: "lax",
|
|
366
|
+
maxAge: client.sessionMaxAge,
|
|
367
|
+
path: "/"
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
return NextResponse.json({ success: true, redirect: "/dashboard" });
|
|
371
|
+
}
|
|
372
|
+
async function mfaTotpSetup() {
|
|
373
|
+
const cookieStore = await cookies2();
|
|
374
|
+
const sessionCookie = cookieStore.get(client.cookieName);
|
|
375
|
+
if (!sessionCookie) {
|
|
376
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
377
|
+
}
|
|
378
|
+
return NextResponse.json(
|
|
379
|
+
{ error: "Call /api/proxy/mfa/totp/setup directly with Bearer JWT" },
|
|
380
|
+
{ status: 400 }
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
async function refresh() {
|
|
384
|
+
const cookieStore = await cookies2();
|
|
385
|
+
const refreshCookie = cookieStore.get(client.refreshTokenCookieName);
|
|
386
|
+
if (!(refreshCookie == null ? void 0 : refreshCookie.value)) {
|
|
387
|
+
return NextResponse.json(
|
|
388
|
+
{ error: "No refresh token" },
|
|
389
|
+
{ status: 401 }
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
const result = await client.refreshToken(refreshCookie.value);
|
|
393
|
+
if (!result) {
|
|
394
|
+
return NextResponse.json(
|
|
395
|
+
{ error: "Invalid refresh token" },
|
|
396
|
+
{ status: 401 }
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
const verified = await client.verifyToken(result.token);
|
|
400
|
+
if (verified.valid && verified.user) {
|
|
401
|
+
await setSession(verified.user);
|
|
402
|
+
}
|
|
403
|
+
return NextResponse.json({ success: true, token: result.token });
|
|
404
|
+
}
|
|
405
|
+
async function logout() {
|
|
406
|
+
const cookieStore = await cookies2();
|
|
407
|
+
const refreshCookie = cookieStore.get(client.refreshTokenCookieName);
|
|
408
|
+
if (refreshCookie == null ? void 0 : refreshCookie.value) {
|
|
409
|
+
await client.revokeSession(refreshCookie.value);
|
|
410
|
+
cookieStore.set(client.refreshTokenCookieName, "", {
|
|
411
|
+
httpOnly: true,
|
|
412
|
+
secure: process.env.NODE_ENV === "production",
|
|
413
|
+
sameSite: "lax",
|
|
414
|
+
maxAge: 0,
|
|
415
|
+
path: "/"
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
await clearSession();
|
|
419
|
+
return NextResponse.redirect(new URL("/", appUrl));
|
|
420
|
+
}
|
|
421
|
+
async function me() {
|
|
422
|
+
const user = await getSession();
|
|
423
|
+
if (!user) {
|
|
424
|
+
return NextResponse.json({ user: null });
|
|
425
|
+
}
|
|
426
|
+
const cookieStore = await cookies2();
|
|
427
|
+
const refreshCookie = cookieStore.get(client.refreshTokenCookieName);
|
|
428
|
+
if (refreshCookie == null ? void 0 : refreshCookie.value) {
|
|
429
|
+
const result = await client.refreshToken(refreshCookie.value);
|
|
430
|
+
if (!result) {
|
|
431
|
+
await clearSession();
|
|
432
|
+
return NextResponse.json({ user: null });
|
|
433
|
+
}
|
|
434
|
+
const verified = await client.verifyToken(result.token);
|
|
435
|
+
if (verified.valid && verified.user) {
|
|
436
|
+
await setSession(verified.user);
|
|
437
|
+
return NextResponse.json({ user: verified.user });
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return NextResponse.json({ user });
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
providerLogin,
|
|
444
|
+
callback,
|
|
445
|
+
emailSignup,
|
|
446
|
+
emailSignin,
|
|
447
|
+
emailForgotPassword,
|
|
448
|
+
emailResetPassword,
|
|
449
|
+
emailVerifyCode,
|
|
450
|
+
magicLinkSend,
|
|
451
|
+
smsSendCode,
|
|
452
|
+
smsVerifyCode,
|
|
453
|
+
mfaVerify,
|
|
454
|
+
mfaTotpSetup,
|
|
455
|
+
refresh,
|
|
456
|
+
logout,
|
|
457
|
+
me
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function createCatchAllHandler(client, appUrl) {
|
|
461
|
+
const handlers = createHandlers(client, appUrl);
|
|
462
|
+
async function GET(request, context) {
|
|
463
|
+
const { authgate: segments } = await context.params;
|
|
464
|
+
const path = segments.join("/");
|
|
465
|
+
if (segments.length === 2 && segments[1] === "login") {
|
|
466
|
+
return handlers.providerLogin(request, {
|
|
467
|
+
params: Promise.resolve({ provider: segments[0] })
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
if (path === "callback") {
|
|
471
|
+
return handlers.callback(request);
|
|
472
|
+
}
|
|
473
|
+
if (path === "me") {
|
|
474
|
+
return handlers.me();
|
|
475
|
+
}
|
|
476
|
+
return NextResponse.json({ error: "Not found" }, { status: 404 });
|
|
477
|
+
}
|
|
478
|
+
async function POST(request, context) {
|
|
479
|
+
const { authgate: segments } = await context.params;
|
|
480
|
+
const path = segments.join("/");
|
|
481
|
+
switch (path) {
|
|
482
|
+
case "email/signup":
|
|
483
|
+
return handlers.emailSignup(request);
|
|
484
|
+
case "email/signin":
|
|
485
|
+
return handlers.emailSignin(request);
|
|
486
|
+
case "email/forgot-password":
|
|
487
|
+
return handlers.emailForgotPassword(request);
|
|
488
|
+
case "email/reset-password":
|
|
489
|
+
return handlers.emailResetPassword(request);
|
|
490
|
+
case "email/verify-code":
|
|
491
|
+
return handlers.emailVerifyCode(request);
|
|
492
|
+
case "magic-link/send":
|
|
493
|
+
return handlers.magicLinkSend(request);
|
|
494
|
+
case "sms/send-code":
|
|
495
|
+
return handlers.smsSendCode(request);
|
|
496
|
+
case "sms/verify-code":
|
|
497
|
+
return handlers.smsVerifyCode(request);
|
|
498
|
+
case "mfa/verify":
|
|
499
|
+
return handlers.mfaVerify(request);
|
|
500
|
+
case "refresh":
|
|
501
|
+
return handlers.refresh();
|
|
502
|
+
case "logout":
|
|
503
|
+
return handlers.logout();
|
|
504
|
+
default:
|
|
505
|
+
return NextResponse.json({ error: "Not found" }, { status: 404 });
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return { GET, POST };
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// src/index.ts
|
|
512
|
+
import { createAuthGateClient as createAuthGateClient2, SUPPORTED_PROVIDERS as SUPPORTED_PROVIDERS2 } from "@auth-gate/core";
|
|
513
|
+
|
|
514
|
+
// src/middleware.ts
|
|
515
|
+
import { NextResponse as NextResponse2 } from "next/server";
|
|
516
|
+
var REVALIDATION_INTERVAL = 300;
|
|
517
|
+
function patternToRegex(pattern) {
|
|
518
|
+
const regexStr = pattern.replace(/\/:(\w+)\*/g, "(?:/.*)?").replace(/\/:(\w+)/g, "/[^/]+");
|
|
519
|
+
return new RegExp(`^${regexStr}$`);
|
|
520
|
+
}
|
|
521
|
+
function matchesPath(pathname, patterns) {
|
|
522
|
+
return patterns.some((p) => patternToRegex(p).test(pathname));
|
|
523
|
+
}
|
|
524
|
+
function redirectToLogin(request, loginPath, client) {
|
|
525
|
+
const loginUrl = new URL(loginPath, request.url);
|
|
526
|
+
loginUrl.searchParams.set("redirect", request.nextUrl.pathname);
|
|
527
|
+
const response = NextResponse2.redirect(loginUrl);
|
|
528
|
+
response.cookies.set(client.cookieName, "", {
|
|
529
|
+
httpOnly: true,
|
|
530
|
+
secure: process.env.NODE_ENV === "production",
|
|
531
|
+
sameSite: "lax",
|
|
532
|
+
maxAge: 0,
|
|
533
|
+
path: "/"
|
|
534
|
+
});
|
|
535
|
+
response.cookies.set(client.refreshTokenCookieName, "", {
|
|
536
|
+
httpOnly: true,
|
|
537
|
+
secure: process.env.NODE_ENV === "production",
|
|
538
|
+
sameSite: "lax",
|
|
539
|
+
maxAge: 0,
|
|
540
|
+
path: "/"
|
|
541
|
+
});
|
|
542
|
+
return response;
|
|
543
|
+
}
|
|
544
|
+
function createAuthGateMiddleware(clientOrGetter, options) {
|
|
545
|
+
var _a, _b;
|
|
546
|
+
const loginPath = (_a = options == null ? void 0 : options.loginPath) != null ? _a : "/login";
|
|
547
|
+
const matcher = (_b = options == null ? void 0 : options.matcher) != null ? _b : ["/dashboard/:path*"];
|
|
548
|
+
const getClient = () => typeof clientOrGetter === "function" ? clientOrGetter() : clientOrGetter;
|
|
549
|
+
return async function authMiddleware(request) {
|
|
550
|
+
if (!matchesPath(request.nextUrl.pathname, matcher)) {
|
|
551
|
+
return null;
|
|
552
|
+
}
|
|
553
|
+
const client = getClient();
|
|
554
|
+
const cookie = request.cookies.get(client.cookieName);
|
|
555
|
+
if (!cookie) {
|
|
556
|
+
return redirectToLogin(request, loginPath, client);
|
|
557
|
+
}
|
|
558
|
+
const payload = await client.decryptSessionPayload(cookie.value);
|
|
559
|
+
if (!payload) {
|
|
560
|
+
return redirectToLogin(request, loginPath, client);
|
|
561
|
+
}
|
|
562
|
+
const refreshCookie = request.cookies.get(client.refreshTokenCookieName);
|
|
563
|
+
if (refreshCookie == null ? void 0 : refreshCookie.value) {
|
|
564
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
565
|
+
const sessionAge = now - payload.iat;
|
|
566
|
+
if (sessionAge >= REVALIDATION_INTERVAL) {
|
|
567
|
+
const result = await client.refreshToken(refreshCookie.value);
|
|
568
|
+
if (!result) {
|
|
569
|
+
return redirectToLogin(request, loginPath, client);
|
|
570
|
+
}
|
|
571
|
+
const verified = await client.verifyToken(result.token);
|
|
572
|
+
if (!verified.valid || !verified.user) {
|
|
573
|
+
return redirectToLogin(request, loginPath, client);
|
|
574
|
+
}
|
|
575
|
+
const newCookieValue = await client.encryptSession(verified.user);
|
|
576
|
+
const response = NextResponse2.next();
|
|
577
|
+
response.cookies.set(
|
|
578
|
+
client.cookieName,
|
|
579
|
+
newCookieValue,
|
|
580
|
+
client.getSessionCookieOptions()
|
|
581
|
+
);
|
|
582
|
+
return response;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return null;
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// src/index.ts
|
|
590
|
+
function createAuthGate(config) {
|
|
591
|
+
const client = createAuthGateClient(config);
|
|
592
|
+
const session = createSessionHelpers(client);
|
|
593
|
+
const handlers = createCatchAllHandler(client, config.appUrl);
|
|
594
|
+
return {
|
|
595
|
+
client,
|
|
596
|
+
handlers,
|
|
597
|
+
session
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
export {
|
|
601
|
+
SUPPORTED_PROVIDERS2 as SUPPORTED_PROVIDERS,
|
|
602
|
+
createAuthGate,
|
|
603
|
+
createAuthGateClient2 as createAuthGateClient,
|
|
604
|
+
createAuthGateMiddleware,
|
|
605
|
+
createCatchAllHandler,
|
|
606
|
+
createHandlers,
|
|
607
|
+
createSessionHelpers
|
|
608
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@auth-gate/nextjs",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"import": "./dist/index.mjs",
|
|
9
|
+
"require": "./dist/index.cjs"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.cjs",
|
|
13
|
+
"module": "./dist/index.mjs",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@auth-gate/core": "0.1.0"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"next": ">=14"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"next": "16.1.6",
|
|
26
|
+
"react": "19.2.3",
|
|
27
|
+
"react-dom": "19.2.3",
|
|
28
|
+
"@types/react": "^19",
|
|
29
|
+
"tsup": "^8.0.0",
|
|
30
|
+
"typescript": "^5"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsup",
|
|
34
|
+
"typecheck": "tsc --noEmit"
|
|
35
|
+
}
|
|
36
|
+
}
|