@neondatabase/auth 0.1.0-beta.14 → 0.1.0-beta.15
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/{adapter-core-BPv4mLT0.mjs → adapter-core-ChIlSbGg.mjs} +126 -1
- package/dist/{adapter-core-9F3bfyWA.d.mts → adapter-core-CtcS7ex8.d.mts} +128 -120
- package/dist/{better-auth-react-adapter-BYvAsZdj.d.mts → better-auth-react-adapter-AucJqubr.d.mts} +7 -7
- package/dist/{better-auth-react-adapter-BkeuhSFt.mjs → better-auth-react-adapter-C3_WRaIy.mjs} +1 -1
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +2 -1
- package/dist/{neon-auth-BhLZg9v8.mjs → neon-auth-sSiNq4zM.mjs} +1 -1
- package/dist/next/index.d.mts +7 -7
- package/dist/next/index.mjs +7 -8
- package/dist/react/adapters/index.d.mts +3 -2
- package/dist/react/adapters/index.mjs +2 -1
- package/dist/react/index.d.mts +3 -2
- package/dist/react/index.mjs +2 -1
- package/dist/{supabase-adapter-_2wgvfZ3.d.mts → supabase-adapter-Bbn88gZj.d.mts} +261 -261
- package/dist/{supabase-adapter-rl2coLdb.mjs → supabase-adapter-DhlcXYb9.mjs} +1 -1
- package/dist/types/index.d.mts +3 -7
- package/dist/vanilla/adapters/index.d.mts +3 -2
- package/dist/vanilla/adapters/index.mjs +2 -1
- package/dist/vanilla/index.d.mts +3 -2
- package/dist/vanilla/index.mjs +2 -1
- package/llms.txt +157 -0
- package/package.json +3 -2
- /package/dist/{better-auth-types-CE4hLv9E.d.mts → better-auth-types-VqadyqlG.d.mts} +0 -0
|
@@ -118,6 +118,14 @@ const CLOCK_SKEW_BUFFER_MS = 1e4;
|
|
|
118
118
|
const DEFAULT_SESSION_EXPIRY_MS = 36e5;
|
|
119
119
|
/** Name of the session verifier parameter in the URL, used for the OAUTH flow */
|
|
120
120
|
const NEON_AUTH_SESSION_VERIFIER_PARAM_NAME = "neon_auth_session_verifier";
|
|
121
|
+
/** Name of the popup marker parameter in the URL, used for OAuth popup flow in iframes */
|
|
122
|
+
const NEON_AUTH_POPUP_PARAM_NAME = "neon_popup";
|
|
123
|
+
/** Name of the original callback URL parameter, used in OAuth popup flow */
|
|
124
|
+
const NEON_AUTH_POPUP_CALLBACK_PARAM_NAME = "neon_popup_callback";
|
|
125
|
+
/** The callback route used for OAuth popup completion (must be in middleware SKIP_ROUTES) */
|
|
126
|
+
const NEON_AUTH_POPUP_CALLBACK_ROUTE = "/auth/callback";
|
|
127
|
+
/** Message type for OAuth popup completion postMessage */
|
|
128
|
+
const OAUTH_POPUP_MESSAGE_TYPE = "neon-auth:oauth-complete";
|
|
121
129
|
|
|
122
130
|
//#endregion
|
|
123
131
|
//#region src/utils/jwt.ts
|
|
@@ -293,6 +301,59 @@ var AnonymousTokenCacheManager = class {
|
|
|
293
301
|
}
|
|
294
302
|
};
|
|
295
303
|
|
|
304
|
+
//#endregion
|
|
305
|
+
//#region src/core/oauth-popup.ts
|
|
306
|
+
/**
|
|
307
|
+
* Opens an OAuth popup window and waits for completion.
|
|
308
|
+
*
|
|
309
|
+
* This is used when the app is running inside an iframe, where OAuth
|
|
310
|
+
* redirect flows don't work due to X-Frame-Options/CSP restrictions.
|
|
311
|
+
* The popup completes the OAuth flow and sends a postMessage back
|
|
312
|
+
* with the session verifier needed to fetch the session.
|
|
313
|
+
*
|
|
314
|
+
* @param url - The OAuth authorization URL to open in the popup
|
|
315
|
+
* @returns Promise that resolves with the session verifier when OAuth completes
|
|
316
|
+
* @throws Error if popup is blocked, closed by user, or times out
|
|
317
|
+
*/
|
|
318
|
+
async function openOAuthPopup(url) {
|
|
319
|
+
const timeout = 12e4;
|
|
320
|
+
const pollInterval = 500;
|
|
321
|
+
return new Promise((resolve, reject) => {
|
|
322
|
+
const popup = globalThis.open(url, "neon_oauth_popup", "width=500,height=700,popup=yes");
|
|
323
|
+
if (!popup || popup.closed) {
|
|
324
|
+
reject(/* @__PURE__ */ new Error("Popup blocked. Please allow popups for this site."));
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const timeoutId = setTimeout(() => {
|
|
328
|
+
cleanup();
|
|
329
|
+
try {
|
|
330
|
+
popup.close();
|
|
331
|
+
} catch {}
|
|
332
|
+
reject(/* @__PURE__ */ new Error("OAuth popup timed out. Please try again."));
|
|
333
|
+
}, timeout);
|
|
334
|
+
const pollId = setInterval(() => {
|
|
335
|
+
try {
|
|
336
|
+
if (popup.closed) {
|
|
337
|
+
cleanup();
|
|
338
|
+
reject(/* @__PURE__ */ new Error("OAuth popup was closed. Please try again."));
|
|
339
|
+
}
|
|
340
|
+
} catch {}
|
|
341
|
+
}, pollInterval);
|
|
342
|
+
function cleanup() {
|
|
343
|
+
clearTimeout(timeoutId);
|
|
344
|
+
clearInterval(pollId);
|
|
345
|
+
globalThis.removeEventListener("message", handleMessage);
|
|
346
|
+
}
|
|
347
|
+
function handleMessage(event) {
|
|
348
|
+
if (event.origin !== globalThis.location.origin) return;
|
|
349
|
+
if (event.data?.type !== OAUTH_POPUP_MESSAGE_TYPE) return;
|
|
350
|
+
cleanup();
|
|
351
|
+
resolve({ verifier: event.data.verifier || null });
|
|
352
|
+
}
|
|
353
|
+
globalThis.addEventListener("message", handleMessage);
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
|
|
296
357
|
//#endregion
|
|
297
358
|
//#region src/utils/browser.ts
|
|
298
359
|
/**
|
|
@@ -302,6 +363,19 @@ var AnonymousTokenCacheManager = class {
|
|
|
302
363
|
const isBrowser = () => {
|
|
303
364
|
return globalThis.window !== void 0 && typeof document !== "undefined";
|
|
304
365
|
};
|
|
366
|
+
/**
|
|
367
|
+
* Checks if the code is running inside an iframe
|
|
368
|
+
* Used to detect embedded contexts where OAuth redirect won't work
|
|
369
|
+
* @returns true if in iframe, false otherwise
|
|
370
|
+
*/
|
|
371
|
+
const isIframe = () => {
|
|
372
|
+
if (!isBrowser()) return false;
|
|
373
|
+
try {
|
|
374
|
+
return globalThis.self !== globalThis.top;
|
|
375
|
+
} catch {
|
|
376
|
+
return true;
|
|
377
|
+
}
|
|
378
|
+
};
|
|
305
379
|
|
|
306
380
|
//#endregion
|
|
307
381
|
//#region src/plugins/anonymous-token.ts
|
|
@@ -341,6 +415,39 @@ const BETTER_AUTH_ENDPOINTS = {
|
|
|
341
415
|
anonymousSignIn: "/sign-in/anonymous",
|
|
342
416
|
anonymousToken: "/token/anonymous"
|
|
343
417
|
};
|
|
418
|
+
/**
|
|
419
|
+
* Handles social sign-in via popup when running inside an iframe.
|
|
420
|
+
* This is necessary because OAuth redirects don't work in iframes due to
|
|
421
|
+
* X-Frame-Options/CSP restrictions from OAuth providers.
|
|
422
|
+
*
|
|
423
|
+
* Flow:
|
|
424
|
+
* 1. Request OAuth URL from server (with disableRedirect)
|
|
425
|
+
* 2. Open popup window with the OAuth URL
|
|
426
|
+
* 3. Wait for popup to complete and send back the session verifier
|
|
427
|
+
* 4. Navigate to callbackURL with verifier - normal page load handles session
|
|
428
|
+
*/
|
|
429
|
+
async function handleSocialSignInViaPopup(input, init) {
|
|
430
|
+
const body = JSON.parse(init?.body || "{}");
|
|
431
|
+
const originalCallbackURL = body.callbackURL || "/";
|
|
432
|
+
const popupCallbackUrl = new URL(NEON_AUTH_POPUP_CALLBACK_ROUTE, globalThis.location.origin);
|
|
433
|
+
popupCallbackUrl.searchParams.set(NEON_AUTH_POPUP_PARAM_NAME, "1");
|
|
434
|
+
popupCallbackUrl.searchParams.set(NEON_AUTH_POPUP_CALLBACK_PARAM_NAME, originalCallbackURL);
|
|
435
|
+
body.callbackURL = popupCallbackUrl.toString();
|
|
436
|
+
body.disableRedirect = true;
|
|
437
|
+
const response = await fetch(input, {
|
|
438
|
+
...init,
|
|
439
|
+
body: JSON.stringify(body)
|
|
440
|
+
});
|
|
441
|
+
const data = await response.json();
|
|
442
|
+
const oauthUrl = data.url;
|
|
443
|
+
if (!oauthUrl) throw new Error("Failed to get OAuth URL");
|
|
444
|
+
const popupResult = await openOAuthPopup(oauthUrl);
|
|
445
|
+
if (!popupResult.verifier) throw new Error("OAuth completed but no session verifier received");
|
|
446
|
+
const navigationUrl = new URL(originalCallbackURL, globalThis.location.origin);
|
|
447
|
+
navigationUrl.searchParams.set(NEON_AUTH_SESSION_VERIFIER_PARAM_NAME, popupResult.verifier);
|
|
448
|
+
globalThis.location.href = navigationUrl.toString();
|
|
449
|
+
return Response.json(data, { status: response.status });
|
|
450
|
+
}
|
|
344
451
|
const BETTER_AUTH_METHODS_HOOKS = {
|
|
345
452
|
signUp: {
|
|
346
453
|
onRequest: () => {},
|
|
@@ -359,6 +466,10 @@ const BETTER_AUTH_METHODS_HOOKS = {
|
|
|
359
466
|
}
|
|
360
467
|
},
|
|
361
468
|
signIn: {
|
|
469
|
+
beforeRequest: (input, init) => {
|
|
470
|
+
if (!(typeof input === "string" ? input : input.toString()).includes("/sign-in/social") || !isIframe()) return null;
|
|
471
|
+
return handleSocialSignInViaPopup(input, init);
|
|
472
|
+
},
|
|
362
473
|
onRequest: () => {},
|
|
363
474
|
onSuccess: (responseData) => {
|
|
364
475
|
if (isSessionResponseData(responseData)) {
|
|
@@ -513,6 +624,20 @@ function deriveBetterAuthMethodFromUrl(url) {
|
|
|
513
624
|
if (url.includes(BETTER_AUTH_ENDPOINTS.getSession) || url.includes(BETTER_AUTH_ENDPOINTS.token)) return "getSession";
|
|
514
625
|
}
|
|
515
626
|
function initBroadcastChannel() {
|
|
627
|
+
if (isBrowser() && globalThis.opener && globalThis.opener !== globalThis) {
|
|
628
|
+
const params = new URLSearchParams(globalThis.location.search);
|
|
629
|
+
if (params.has(NEON_AUTH_POPUP_PARAM_NAME)) {
|
|
630
|
+
const verifier = params.get(NEON_AUTH_SESSION_VERIFIER_PARAM_NAME);
|
|
631
|
+
const originalCallback = params.get(NEON_AUTH_POPUP_CALLBACK_PARAM_NAME);
|
|
632
|
+
globalThis.opener.postMessage({
|
|
633
|
+
type: OAUTH_POPUP_MESSAGE_TYPE,
|
|
634
|
+
verifier,
|
|
635
|
+
originalCallback
|
|
636
|
+
}, "*");
|
|
637
|
+
globalThis.close();
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
516
641
|
getGlobalBroadcastChannel().subscribe((message) => {
|
|
517
642
|
if (message.clientId === CURRENT_TAB_CLIENT_ID) return;
|
|
518
643
|
const trigger = message.data?.trigger;
|
|
@@ -615,4 +740,4 @@ var NeonAuthAdapterCore = class {
|
|
|
615
740
|
};
|
|
616
741
|
|
|
617
742
|
//#endregion
|
|
618
|
-
export { DEFAULT_SESSION_EXPIRY_MS as a, CURRENT_TAB_CLIENT_ID as i, BETTER_AUTH_METHODS_CACHE as n, BETTER_AUTH_METHODS_HOOKS as r, NeonAuthAdapterCore as t };
|
|
743
|
+
export { DEFAULT_SESSION_EXPIRY_MS as a, CURRENT_TAB_CLIENT_ID as i, BETTER_AUTH_METHODS_CACHE as n, NEON_AUTH_SESSION_VERIFIER_PARAM_NAME as o, BETTER_AUTH_METHODS_HOOKS as r, NeonAuthAdapterCore as t };
|