@payez/next-mvp 4.0.27 → 4.0.28
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/auth/better-auth.d.ts +18 -0
- package/dist/auth/better-auth.js +62 -0
- package/package.json +1 -1
- package/src/auth/better-auth.ts +66 -0
|
@@ -108,3 +108,21 @@ export declare function getBetterAuthHandler(): Promise<{
|
|
|
108
108
|
* This replaces the old databaseHooks approach which doesn't fire in stateless mode.
|
|
109
109
|
*/
|
|
110
110
|
export declare function exchangeOAuthForIdpTokens(sessionToken: string, provider?: string): Promise<boolean>;
|
|
111
|
+
/**
|
|
112
|
+
* Create a production-ready GET handler for the auth catch-all route.
|
|
113
|
+
*
|
|
114
|
+
* Wraps better-auth's GET handler with:
|
|
115
|
+
* - OAuth state error recovery (redirects to login instead of error page)
|
|
116
|
+
* - IDP token exchange after successful OAuth callback
|
|
117
|
+
*
|
|
118
|
+
* Usage in host app:
|
|
119
|
+
* ```ts
|
|
120
|
+
* import { createAuthGetHandler, getBetterAuthHandler } from '@payez/next-mvp/auth/better-auth';
|
|
121
|
+
* export const GET = createAuthGetHandler('/account-auth/login');
|
|
122
|
+
* export async function POST(req: Request) {
|
|
123
|
+
* const ba = await getBetterAuthHandler();
|
|
124
|
+
* return ba!.POST(req);
|
|
125
|
+
* }
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export declare function createAuthGetHandler(loginPath?: string): (request: Request) => Promise<Response>;
|
package/dist/auth/better-auth.js
CHANGED
|
@@ -17,6 +17,7 @@ exports.isBetterAuthEnabled = isBetterAuthEnabled;
|
|
|
17
17
|
exports.getBetterAuthInstance = getBetterAuthInstance;
|
|
18
18
|
exports.getBetterAuthHandler = getBetterAuthHandler;
|
|
19
19
|
exports.exchangeOAuthForIdpTokens = exchangeOAuthForIdpTokens;
|
|
20
|
+
exports.createAuthGetHandler = createAuthGetHandler;
|
|
20
21
|
require("server-only");
|
|
21
22
|
const better_auth_1 = require("better-auth");
|
|
22
23
|
const next_js_1 = require("better-auth/next-js");
|
|
@@ -257,3 +258,64 @@ async function exchangeOAuthForIdpTokens(sessionToken, provider = 'google') {
|
|
|
257
258
|
return false;
|
|
258
259
|
}
|
|
259
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Create a production-ready GET handler for the auth catch-all route.
|
|
263
|
+
*
|
|
264
|
+
* Wraps better-auth's GET handler with:
|
|
265
|
+
* - OAuth state error recovery (redirects to login instead of error page)
|
|
266
|
+
* - IDP token exchange after successful OAuth callback
|
|
267
|
+
*
|
|
268
|
+
* Usage in host app:
|
|
269
|
+
* ```ts
|
|
270
|
+
* import { createAuthGetHandler, getBetterAuthHandler } from '@payez/next-mvp/auth/better-auth';
|
|
271
|
+
* export const GET = createAuthGetHandler('/account-auth/login');
|
|
272
|
+
* export async function POST(req: Request) {
|
|
273
|
+
* const ba = await getBetterAuthHandler();
|
|
274
|
+
* return ba!.POST(req);
|
|
275
|
+
* }
|
|
276
|
+
* ```
|
|
277
|
+
*/
|
|
278
|
+
function createAuthGetHandler(loginPath = '/account-auth/login') {
|
|
279
|
+
return async function GET(request) {
|
|
280
|
+
const ba = await getBetterAuthHandler();
|
|
281
|
+
if (!ba) {
|
|
282
|
+
return new Response('Auth handler not configured', { status: 500 });
|
|
283
|
+
}
|
|
284
|
+
const response = await ba.GET(request);
|
|
285
|
+
// Intercept auth errors (state mismatch, expired cookies) — redirect to login cleanly
|
|
286
|
+
if (response.status === 302) {
|
|
287
|
+
const location = response.headers.get('location') || '';
|
|
288
|
+
if (location.includes('/api/auth/error') || location.includes('please_restart')) {
|
|
289
|
+
console.warn('[BETTER_AUTH] OAuth state error, redirecting to login');
|
|
290
|
+
return Response.redirect(new URL(loginPath, request.url), 302);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// After successful OAuth callback: exchange Google identity for IDP tokens
|
|
294
|
+
const url = new URL(request.url);
|
|
295
|
+
if (url.pathname.includes('/callback/') && response.status === 302) {
|
|
296
|
+
try {
|
|
297
|
+
const auth = await getBetterAuthInstance();
|
|
298
|
+
if (auth?.api?.getSession) {
|
|
299
|
+
const setCookies = response.headers.getSetCookie?.() || [];
|
|
300
|
+
const cookieHeader = setCookies
|
|
301
|
+
.map((c) => c.split(';')[0])
|
|
302
|
+
.join('; ');
|
|
303
|
+
const headers = new Headers();
|
|
304
|
+
headers.set('cookie', cookieHeader);
|
|
305
|
+
const session = await auth.api.getSession({ headers });
|
|
306
|
+
if (session?.session?.token) {
|
|
307
|
+
console.log('[BETTER_AUTH] Got session token from callback:', session.session.token.substring(0, 10), '| email:', session.user?.email);
|
|
308
|
+
await exchangeOAuthForIdpTokens(session.session.token);
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
console.warn('[BETTER_AUTH] Could not get session after OAuth callback');
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
catch (err) {
|
|
316
|
+
console.error('[BETTER_AUTH] IDP token exchange failed:', err.message);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return response;
|
|
320
|
+
};
|
|
321
|
+
}
|
package/package.json
CHANGED
package/src/auth/better-auth.ts
CHANGED
|
@@ -283,3 +283,69 @@ export async function exchangeOAuthForIdpTokens(
|
|
|
283
283
|
return false;
|
|
284
284
|
}
|
|
285
285
|
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Create a production-ready GET handler for the auth catch-all route.
|
|
289
|
+
*
|
|
290
|
+
* Wraps better-auth's GET handler with:
|
|
291
|
+
* - OAuth state error recovery (redirects to login instead of error page)
|
|
292
|
+
* - IDP token exchange after successful OAuth callback
|
|
293
|
+
*
|
|
294
|
+
* Usage in host app:
|
|
295
|
+
* ```ts
|
|
296
|
+
* import { createAuthGetHandler, getBetterAuthHandler } from '@payez/next-mvp/auth/better-auth';
|
|
297
|
+
* export const GET = createAuthGetHandler('/account-auth/login');
|
|
298
|
+
* export async function POST(req: Request) {
|
|
299
|
+
* const ba = await getBetterAuthHandler();
|
|
300
|
+
* return ba!.POST(req);
|
|
301
|
+
* }
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
export function createAuthGetHandler(loginPath: string = '/account-auth/login') {
|
|
305
|
+
return async function GET(request: Request): Promise<Response> {
|
|
306
|
+
const ba = await getBetterAuthHandler();
|
|
307
|
+
if (!ba) {
|
|
308
|
+
return new Response('Auth handler not configured', { status: 500 });
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const response = await ba.GET(request);
|
|
312
|
+
|
|
313
|
+
// Intercept auth errors (state mismatch, expired cookies) — redirect to login cleanly
|
|
314
|
+
if (response.status === 302) {
|
|
315
|
+
const location = response.headers.get('location') || '';
|
|
316
|
+
if (location.includes('/api/auth/error') || location.includes('please_restart')) {
|
|
317
|
+
console.warn('[BETTER_AUTH] OAuth state error, redirecting to login');
|
|
318
|
+
return Response.redirect(new URL(loginPath, request.url), 302);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// After successful OAuth callback: exchange Google identity for IDP tokens
|
|
323
|
+
const url = new URL(request.url);
|
|
324
|
+
if (url.pathname.includes('/callback/') && response.status === 302) {
|
|
325
|
+
try {
|
|
326
|
+
const auth = await getBetterAuthInstance();
|
|
327
|
+
if (auth?.api?.getSession) {
|
|
328
|
+
const setCookies = response.headers.getSetCookie?.() || [];
|
|
329
|
+
const cookieHeader = setCookies
|
|
330
|
+
.map((c: string) => c.split(';')[0])
|
|
331
|
+
.join('; ');
|
|
332
|
+
|
|
333
|
+
const headers = new Headers();
|
|
334
|
+
headers.set('cookie', cookieHeader);
|
|
335
|
+
|
|
336
|
+
const session = await auth.api.getSession({ headers });
|
|
337
|
+
if (session?.session?.token) {
|
|
338
|
+
console.log('[BETTER_AUTH] Got session token from callback:', session.session.token.substring(0, 10), '| email:', session.user?.email);
|
|
339
|
+
await exchangeOAuthForIdpTokens(session.session.token);
|
|
340
|
+
} else {
|
|
341
|
+
console.warn('[BETTER_AUTH] Could not get session after OAuth callback');
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
} catch (err: any) {
|
|
345
|
+
console.error('[BETTER_AUTH] IDP token exchange failed:', err.message);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return response;
|
|
350
|
+
};
|
|
351
|
+
}
|