@bagelink/auth 1.7.76 → 1.7.80

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/README.md CHANGED
@@ -294,7 +294,7 @@ await sso.google.redirect({
294
294
  // router.ts
295
295
  {
296
296
  path: '/auth/callback',
297
- name: 'Callback',
297
+ name: 'AuthCallback',
298
298
  component: () => import('@bagelink/auth').then(m => m.Callback),
299
299
  }
300
300
  ```
@@ -308,6 +308,31 @@ await sso.google.redirect({
308
308
  - Okta
309
309
  - Facebook
310
310
 
311
+ ### SSO Redirect Preservation
312
+
313
+ When users access a protected route and authenticate via SSO, the original URL is automatically preserved:
314
+
315
+ ```typescript
316
+ // User tries to access /dashboard (protected)
317
+ // ↓ Redirected to /login?redirect=/dashboard
318
+ // ↓ User clicks "Login with Google"
319
+ // ↓ Goes to Google OAuth
320
+ // ↓ Returns to /auth/callback
321
+ // ↓ Automatically redirected to /dashboard ✅
322
+ ```
323
+
324
+ **How it works:**
325
+ 1. The `redirect` query param is stored in `sessionStorage` before SSO redirect
326
+ 2. After OAuth callback, it's restored to the URL
327
+ 3. Auto-redirect (or manual fallback) uses it to navigate to the original destination
328
+
329
+ **Manual SSO with redirect:**
330
+ ```typescript
331
+ // On login page with ?redirect=/dashboard
332
+ await sso.google.redirect()
333
+ // Redirect param is automatically preserved across the OAuth flow
334
+ ```
335
+
311
336
  ## Advanced Configuration
312
337
 
313
338
  ### Security: Restrict Redirect Paths
package/dist/index.cjs CHANGED
@@ -1086,10 +1086,14 @@ const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
1086
1086
  });
1087
1087
  async function linkCallback() {
1088
1088
  isLinking.value = true;
1089
+ const { redirect: redirect2 } = route.query;
1089
1090
  try {
1090
1091
  await sso2.handleLinkCallback();
1091
1092
  success.value = true;
1092
- setTimeout(() => router2.push("/"), timeout);
1093
+ setTimeout(() => {
1094
+ const redirectPath = typeof redirect2 === "string" ? redirect2 : "/";
1095
+ router2.push(redirectPath);
1096
+ }, timeout);
1093
1097
  } catch (err) {
1094
1098
  const errorMessage = err instanceof Error ? err.message : "Failed to link account";
1095
1099
  error.value = errorMessage;
@@ -1099,8 +1103,10 @@ const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
1099
1103
  }
1100
1104
  async function handleCallback() {
1101
1105
  var _a;
1102
- const { state } = route.query;
1106
+ const { state, redirect: redirect2 } = route.query;
1103
1107
  provider.value = sessionStorage.getItem(`oauth_provider:${state}`);
1108
+ console.log("[Callback] Query params:", { state, redirect: redirect2 });
1109
+ console.log("[Callback] Full route query:", route.query);
1104
1110
  try {
1105
1111
  const response = await sso2.handleCallback();
1106
1112
  if (response === null) {
@@ -1108,7 +1114,12 @@ const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
1108
1114
  } else {
1109
1115
  authResponse.value = response;
1110
1116
  success.value = true;
1111
- setTimeout(() => router2.push("/"), timeout);
1117
+ console.log("[Callback] Login successful, redirect param:", redirect2);
1118
+ setTimeout(() => {
1119
+ const redirectPath = typeof redirect2 === "string" ? redirect2 : "/";
1120
+ console.log("[Callback] Manual fallback redirecting to:", redirectPath);
1121
+ router2.push(redirectPath);
1122
+ }, timeout);
1112
1123
  }
1113
1124
  } catch (err) {
1114
1125
  const errorMessage = err instanceof Error ? err.message : "Authentication failed";
@@ -1418,11 +1429,15 @@ function isValidRedirect(redirectUrl, allowedPaths) {
1418
1429
  }
1419
1430
  async function performRedirect(router2, config) {
1420
1431
  const redirect2 = getRedirectUrl(router2, config);
1432
+ console.log("[PerformRedirect] Current route query:", router2.currentRoute.value.query);
1433
+ console.log("[PerformRedirect] Redirect URL:", redirect2);
1434
+ console.log("[PerformRedirect] Config fallback:", config.fallback);
1421
1435
  if (redirect2 !== config.fallback && !isValidRedirect(redirect2, config.allowedPaths)) {
1422
1436
  console.warn("[Auth] Invalid redirect URL detected, using fallback:", redirect2);
1423
1437
  await router2.push(config.fallback);
1424
1438
  return;
1425
1439
  }
1440
+ console.log("[PerformRedirect] Redirecting to:", redirect2);
1426
1441
  await router2.push(redirect2);
1427
1442
  }
1428
1443
  function buildLoginQuery(currentPath, config) {
@@ -1584,6 +1599,16 @@ function createSSOProvider(config) {
1584
1599
  const auth = getAuthApi();
1585
1600
  const redirectUri = options.redirectUri ?? getDefaultRedirectUri();
1586
1601
  const state = options.state ?? generateState();
1602
+ if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
1603
+ const currentParams = queryParams();
1604
+ const redirectUrl = currentParams.redirect;
1605
+ if (redirectUrl) {
1606
+ console.log("[SSO] Preserving redirect URL:", redirectUrl, "with state:", state);
1607
+ sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl);
1608
+ } else {
1609
+ console.log("[SSO] No redirect URL found in current params:", currentParams);
1610
+ }
1611
+ }
1587
1612
  if (typeof sessionStorage !== "undefined") {
1588
1613
  sessionStorage.setItem(getStateKey(), state);
1589
1614
  sessionStorage.setItem(`oauth_provider:${state}`, config.id);
@@ -1602,6 +1627,13 @@ function createSSOProvider(config) {
1602
1627
  const redirectUri = options.redirectUri ?? getDefaultRedirectUri();
1603
1628
  const state = options.state ?? generateState();
1604
1629
  const timeout2 = options.popupTimeout ?? 9e4;
1630
+ if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
1631
+ const currentParams = queryParams();
1632
+ const redirectUrl = currentParams.redirect;
1633
+ if (redirectUrl) {
1634
+ sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl);
1635
+ }
1636
+ }
1605
1637
  if (typeof sessionStorage !== "undefined") {
1606
1638
  sessionStorage.setItem(getStateKey(), state);
1607
1639
  sessionStorage.setItem(`oauth_provider:${state}`, config.id);
@@ -1818,6 +1850,20 @@ function handleOAuthCallback() {
1818
1850
  if (!provider || !isSupportedProvider(provider)) {
1819
1851
  throw new Error("Unable to determine OAuth provider. State may have expired.");
1820
1852
  }
1853
+ if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
1854
+ const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`);
1855
+ if (storedRedirect) {
1856
+ console.log("[SSO] Restoring redirect URL:", storedRedirect);
1857
+ const url = new URL(window.location.href);
1858
+ url.searchParams.set("redirect", storedRedirect);
1859
+ window.history.replaceState({}, "", url.toString());
1860
+ console.log("[SSO] URL updated to:", url.toString());
1861
+ sessionStorage.removeItem(`oauth_redirect:${state}`);
1862
+ } else {
1863
+ console.log("[SSO] No stored redirect URL found for state:", state);
1864
+ console.log("[SSO] SessionStorage keys:", Object.keys(sessionStorage));
1865
+ }
1866
+ }
1821
1867
  return ssoProviders[provider].callback(code, state);
1822
1868
  }
1823
1869
  function handleOAuthLinkCallback() {
@@ -1829,6 +1875,15 @@ function handleOAuthLinkCallback() {
1829
1875
  if (!provider || !isSupportedProvider(provider)) {
1830
1876
  throw new Error("Unable to determine OAuth provider. State may have expired.");
1831
1877
  }
1878
+ if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
1879
+ const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`);
1880
+ if (storedRedirect) {
1881
+ const url = new URL(window.location.href);
1882
+ url.searchParams.set("redirect", storedRedirect);
1883
+ window.history.replaceState({}, "", url.toString());
1884
+ sessionStorage.removeItem(`oauth_redirect:${state}`);
1885
+ }
1886
+ }
1832
1887
  return ssoProviders[provider].link(code, state);
1833
1888
  }
1834
1889
  var AuthState = /* @__PURE__ */ ((AuthState2) => {
@@ -1891,7 +1946,7 @@ function accountToUser(account) {
1891
1946
  const DEFAULT_REDIRECT_CONFIG = {
1892
1947
  queryKey: "redirect",
1893
1948
  fallback: "/",
1894
- noAuthRoutes: ["Login", "Signup", "ForgotPassword", "ResetPassword", "Callback"],
1949
+ noAuthRoutes: ["Login", "Signup", "ForgotPassword", "ResetPassword", "AuthCallback"],
1895
1950
  authenticatedRedirect: "/",
1896
1951
  loginRoute: "Login",
1897
1952
  authMetaKey: "auth",
@@ -2019,7 +2074,7 @@ function setupAutoRedirect() {
2019
2074
  if (!eventEmitter || !redirectConfig) return;
2020
2075
  eventEmitter.on(AuthState.LOGIN, async () => {
2021
2076
  if (!autoRedirectRouter) {
2022
- console.warn("[Auth] Auto-redirect enabled but router not set. Call setAuthRouter(router) in your app setup.");
2077
+ console.warn("[Auth] Auto-redirect enabled but router not set. Call auth.use(router) in your app setup.");
2023
2078
  return;
2024
2079
  }
2025
2080
  const { performRedirect: performRedirect2 } = await Promise.resolve().then(() => redirect);
package/dist/index.mjs CHANGED
@@ -1084,10 +1084,14 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
1084
1084
  });
1085
1085
  async function linkCallback() {
1086
1086
  isLinking.value = true;
1087
+ const { redirect: redirect2 } = route.query;
1087
1088
  try {
1088
1089
  await sso2.handleLinkCallback();
1089
1090
  success.value = true;
1090
- setTimeout(() => router2.push("/"), timeout);
1091
+ setTimeout(() => {
1092
+ const redirectPath = typeof redirect2 === "string" ? redirect2 : "/";
1093
+ router2.push(redirectPath);
1094
+ }, timeout);
1091
1095
  } catch (err) {
1092
1096
  const errorMessage = err instanceof Error ? err.message : "Failed to link account";
1093
1097
  error.value = errorMessage;
@@ -1097,8 +1101,10 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
1097
1101
  }
1098
1102
  async function handleCallback() {
1099
1103
  var _a;
1100
- const { state } = route.query;
1104
+ const { state, redirect: redirect2 } = route.query;
1101
1105
  provider.value = sessionStorage.getItem(`oauth_provider:${state}`);
1106
+ console.log("[Callback] Query params:", { state, redirect: redirect2 });
1107
+ console.log("[Callback] Full route query:", route.query);
1102
1108
  try {
1103
1109
  const response = await sso2.handleCallback();
1104
1110
  if (response === null) {
@@ -1106,7 +1112,12 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
1106
1112
  } else {
1107
1113
  authResponse.value = response;
1108
1114
  success.value = true;
1109
- setTimeout(() => router2.push("/"), timeout);
1115
+ console.log("[Callback] Login successful, redirect param:", redirect2);
1116
+ setTimeout(() => {
1117
+ const redirectPath = typeof redirect2 === "string" ? redirect2 : "/";
1118
+ console.log("[Callback] Manual fallback redirecting to:", redirectPath);
1119
+ router2.push(redirectPath);
1120
+ }, timeout);
1110
1121
  }
1111
1122
  } catch (err) {
1112
1123
  const errorMessage = err instanceof Error ? err.message : "Authentication failed";
@@ -1416,11 +1427,15 @@ function isValidRedirect(redirectUrl, allowedPaths) {
1416
1427
  }
1417
1428
  async function performRedirect(router2, config) {
1418
1429
  const redirect2 = getRedirectUrl(router2, config);
1430
+ console.log("[PerformRedirect] Current route query:", router2.currentRoute.value.query);
1431
+ console.log("[PerformRedirect] Redirect URL:", redirect2);
1432
+ console.log("[PerformRedirect] Config fallback:", config.fallback);
1419
1433
  if (redirect2 !== config.fallback && !isValidRedirect(redirect2, config.allowedPaths)) {
1420
1434
  console.warn("[Auth] Invalid redirect URL detected, using fallback:", redirect2);
1421
1435
  await router2.push(config.fallback);
1422
1436
  return;
1423
1437
  }
1438
+ console.log("[PerformRedirect] Redirecting to:", redirect2);
1424
1439
  await router2.push(redirect2);
1425
1440
  }
1426
1441
  function buildLoginQuery(currentPath, config) {
@@ -1582,6 +1597,16 @@ function createSSOProvider(config) {
1582
1597
  const auth = getAuthApi();
1583
1598
  const redirectUri = options.redirectUri ?? getDefaultRedirectUri();
1584
1599
  const state = options.state ?? generateState();
1600
+ if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
1601
+ const currentParams = queryParams();
1602
+ const redirectUrl = currentParams.redirect;
1603
+ if (redirectUrl) {
1604
+ console.log("[SSO] Preserving redirect URL:", redirectUrl, "with state:", state);
1605
+ sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl);
1606
+ } else {
1607
+ console.log("[SSO] No redirect URL found in current params:", currentParams);
1608
+ }
1609
+ }
1585
1610
  if (typeof sessionStorage !== "undefined") {
1586
1611
  sessionStorage.setItem(getStateKey(), state);
1587
1612
  sessionStorage.setItem(`oauth_provider:${state}`, config.id);
@@ -1600,6 +1625,13 @@ function createSSOProvider(config) {
1600
1625
  const redirectUri = options.redirectUri ?? getDefaultRedirectUri();
1601
1626
  const state = options.state ?? generateState();
1602
1627
  const timeout2 = options.popupTimeout ?? 9e4;
1628
+ if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
1629
+ const currentParams = queryParams();
1630
+ const redirectUrl = currentParams.redirect;
1631
+ if (redirectUrl) {
1632
+ sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl);
1633
+ }
1634
+ }
1603
1635
  if (typeof sessionStorage !== "undefined") {
1604
1636
  sessionStorage.setItem(getStateKey(), state);
1605
1637
  sessionStorage.setItem(`oauth_provider:${state}`, config.id);
@@ -1816,6 +1848,20 @@ function handleOAuthCallback() {
1816
1848
  if (!provider || !isSupportedProvider(provider)) {
1817
1849
  throw new Error("Unable to determine OAuth provider. State may have expired.");
1818
1850
  }
1851
+ if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
1852
+ const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`);
1853
+ if (storedRedirect) {
1854
+ console.log("[SSO] Restoring redirect URL:", storedRedirect);
1855
+ const url = new URL(window.location.href);
1856
+ url.searchParams.set("redirect", storedRedirect);
1857
+ window.history.replaceState({}, "", url.toString());
1858
+ console.log("[SSO] URL updated to:", url.toString());
1859
+ sessionStorage.removeItem(`oauth_redirect:${state}`);
1860
+ } else {
1861
+ console.log("[SSO] No stored redirect URL found for state:", state);
1862
+ console.log("[SSO] SessionStorage keys:", Object.keys(sessionStorage));
1863
+ }
1864
+ }
1819
1865
  return ssoProviders[provider].callback(code, state);
1820
1866
  }
1821
1867
  function handleOAuthLinkCallback() {
@@ -1827,6 +1873,15 @@ function handleOAuthLinkCallback() {
1827
1873
  if (!provider || !isSupportedProvider(provider)) {
1828
1874
  throw new Error("Unable to determine OAuth provider. State may have expired.");
1829
1875
  }
1876
+ if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
1877
+ const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`);
1878
+ if (storedRedirect) {
1879
+ const url = new URL(window.location.href);
1880
+ url.searchParams.set("redirect", storedRedirect);
1881
+ window.history.replaceState({}, "", url.toString());
1882
+ sessionStorage.removeItem(`oauth_redirect:${state}`);
1883
+ }
1884
+ }
1830
1885
  return ssoProviders[provider].link(code, state);
1831
1886
  }
1832
1887
  var AuthState = /* @__PURE__ */ ((AuthState2) => {
@@ -1889,7 +1944,7 @@ function accountToUser(account) {
1889
1944
  const DEFAULT_REDIRECT_CONFIG = {
1890
1945
  queryKey: "redirect",
1891
1946
  fallback: "/",
1892
- noAuthRoutes: ["Login", "Signup", "ForgotPassword", "ResetPassword", "Callback"],
1947
+ noAuthRoutes: ["Login", "Signup", "ForgotPassword", "ResetPassword", "AuthCallback"],
1893
1948
  authenticatedRedirect: "/",
1894
1949
  loginRoute: "Login",
1895
1950
  authMetaKey: "auth",
@@ -2017,7 +2072,7 @@ function setupAutoRedirect() {
2017
2072
  if (!eventEmitter || !redirectConfig) return;
2018
2073
  eventEmitter.on(AuthState.LOGIN, async () => {
2019
2074
  if (!autoRedirectRouter) {
2020
- console.warn("[Auth] Auto-redirect enabled but router not set. Call setAuthRouter(router) in your app setup.");
2075
+ console.warn("[Auth] Auto-redirect enabled but router not set. Call auth.use(router) in your app setup.");
2021
2076
  return;
2022
2077
  }
2023
2078
  const { performRedirect: performRedirect2 } = await Promise.resolve().then(() => redirect);
@@ -16,7 +16,7 @@ export interface RedirectConfig {
16
16
  /**
17
17
  * Routes that require NO authentication (login, signup, forgot password, etc)
18
18
  * Authenticated users will be automatically redirected away from these pages
19
- * @default ['Login', 'Signup', 'ForgotPassword', 'ResetPassword', 'Callback']
19
+ * @default ['Login', 'Signup', 'ForgotPassword', 'ResetPassword', 'AuthCallback']
20
20
  */
21
21
  noAuthRoutes?: string[];
22
22
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/auth",
3
3
  "type": "module",
4
- "version": "1.7.76",
4
+ "version": "1.7.80",
5
5
  "description": "Bagelink auth package",
6
6
  "author": {
7
7
  "name": "Bagel Studio",
@@ -26,10 +26,14 @@ const providerInfo = computed(() => {
26
26
 
27
27
  async function linkCallback() {
28
28
  isLinking.value = true
29
+ const { redirect } = route.query
29
30
  try {
30
31
  await sso.handleLinkCallback()
31
32
  success.value = true
32
- setTimeout(() => router.push('/'), timeout)
33
+ setTimeout(() => {
34
+ const redirectPath = typeof redirect === 'string' ? redirect : '/'
35
+ router.push(redirectPath)
36
+ }, timeout)
33
37
  } catch (err: unknown) {
34
38
  const errorMessage = err instanceof Error ? err.message : 'Failed to link account'
35
39
  error.value = errorMessage
@@ -39,8 +43,10 @@ async function linkCallback() {
39
43
  }
40
44
 
41
45
  async function handleCallback() {
42
- const { state } = route.query
46
+ const { state, redirect } = route.query
43
47
  provider.value = sessionStorage.getItem(`oauth_provider:${state}`) as SSOProvider
48
+ console.log('[Callback] Query params:', { state, redirect })
49
+ console.log('[Callback] Full route query:', route.query)
44
50
 
45
51
  try {
46
52
  const response = await sso.handleCallback()
@@ -49,7 +55,14 @@ async function handleCallback() {
49
55
  } else {
50
56
  authResponse.value = response
51
57
  success.value = true
52
- setTimeout(() => router.push('/'), timeout)
58
+ console.log('[Callback] Login successful, redirect param:', redirect)
59
+ // Auto-redirect will handle navigation, but fallback to manual redirect
60
+ // if auto-redirect is disabled or router not connected
61
+ setTimeout(() => {
62
+ const redirectPath = typeof redirect === 'string' ? redirect : '/'
63
+ console.log('[Callback] Manual fallback redirecting to:', redirectPath)
64
+ router.push(redirectPath)
65
+ }, timeout)
53
66
  }
54
67
  } catch (err: unknown) {
55
68
  const errorMessage = err instanceof Error ? err.message : 'Authentication failed'
package/src/redirect.ts CHANGED
@@ -64,6 +64,9 @@ export async function performRedirect(
64
64
  config: NormalizedRedirectConfig,
65
65
  ): Promise<void> {
66
66
  const redirect = getRedirectUrl(router, config)
67
+ console.log('[PerformRedirect] Current route query:', router.currentRoute.value.query)
68
+ console.log('[PerformRedirect] Redirect URL:', redirect)
69
+ console.log('[PerformRedirect] Config fallback:', config.fallback)
67
70
 
68
71
  // Always validate redirect URL for security
69
72
  if (redirect !== config.fallback && !isValidRedirect(redirect, config.allowedPaths)) {
@@ -72,6 +75,7 @@ export async function performRedirect(
72
75
  return
73
76
  }
74
77
 
78
+ console.log('[PerformRedirect] Redirecting to:', redirect)
75
79
  await router.push(redirect)
76
80
  }
77
81
 
package/src/sso.ts CHANGED
@@ -314,6 +314,19 @@ function createSSOProvider(config: SSOProviderConfig): SSOProviderInstance {
314
314
  const redirectUri = options.redirectUri ?? getDefaultRedirectUri()
315
315
  const state = options.state ?? generateState()
316
316
 
317
+ // Preserve redirect URL from current location
318
+ if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {
319
+ const currentParams = queryParams()
320
+ const redirectUrl = currentParams.redirect
321
+ if (redirectUrl) {
322
+ // Store redirect URL to restore after OAuth callback
323
+ console.log('[SSO] Preserving redirect URL:', redirectUrl, 'with state:', state)
324
+ sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl)
325
+ } else {
326
+ console.log('[SSO] No redirect URL found in current params:', currentParams)
327
+ }
328
+ }
329
+
317
330
  // Store state AND provider in sessionStorage for verification
318
331
  if (typeof sessionStorage !== 'undefined') {
319
332
  sessionStorage.setItem(getStateKey(), state)
@@ -338,6 +351,16 @@ function createSSOProvider(config: SSOProviderConfig): SSOProviderInstance {
338
351
  const state = options.state ?? generateState()
339
352
  const timeout = options.popupTimeout ?? 90000
340
353
 
354
+ // Preserve redirect URL from current location (for popup flow too)
355
+ if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {
356
+ const currentParams = queryParams()
357
+ const redirectUrl = currentParams.redirect
358
+ if (redirectUrl) {
359
+ // Store redirect URL to restore after OAuth callback
360
+ sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl)
361
+ }
362
+ }
363
+
341
364
  // Store state AND provider in sessionStorage for verification
342
365
  if (typeof sessionStorage !== 'undefined') {
343
366
  sessionStorage.setItem(getStateKey(), state)
@@ -615,6 +638,24 @@ function handleOAuthCallback(): Promise<AuthenticationResponse | null> {
615
638
  throw new Error('Unable to determine OAuth provider. State may have expired.')
616
639
  }
617
640
 
641
+ // Restore redirect URL to current location if it was stored
642
+ if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {
643
+ const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`)
644
+ if (storedRedirect) {
645
+ // Add redirect param back to URL so auto-redirect can pick it up
646
+ console.log('[SSO] Restoring redirect URL:', storedRedirect)
647
+ const url = new URL(window.location.href)
648
+ url.searchParams.set('redirect', storedRedirect)
649
+ window.history.replaceState({}, '', url.toString())
650
+ console.log('[SSO] URL updated to:', url.toString())
651
+ // Clean up
652
+ sessionStorage.removeItem(`oauth_redirect:${state}`)
653
+ } else {
654
+ console.log('[SSO] No stored redirect URL found for state:', state)
655
+ console.log('[SSO] SessionStorage keys:', Object.keys(sessionStorage))
656
+ }
657
+ }
658
+
618
659
  return ssoProviders[provider].callback(code, state)
619
660
  }
620
661
 
@@ -636,5 +677,18 @@ function handleOAuthLinkCallback(): Promise<void> {
636
677
  throw new Error('Unable to determine OAuth provider. State may have expired.')
637
678
  }
638
679
 
680
+ // Restore redirect URL to current location if it was stored
681
+ if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {
682
+ const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`)
683
+ if (storedRedirect) {
684
+ // Add redirect param back to URL
685
+ const url = new URL(window.location.href)
686
+ url.searchParams.set('redirect', storedRedirect)
687
+ window.history.replaceState({}, '', url.toString())
688
+ // Clean up
689
+ sessionStorage.removeItem(`oauth_redirect:${state}`)
690
+ }
691
+ }
692
+
639
693
  return ssoProviders[provider].link(code, state)
640
694
  }
@@ -19,7 +19,7 @@ export interface RedirectConfig {
19
19
  /**
20
20
  * Routes that require NO authentication (login, signup, forgot password, etc)
21
21
  * Authenticated users will be automatically redirected away from these pages
22
- * @default ['Login', 'Signup', 'ForgotPassword', 'ResetPassword', 'Callback']
22
+ * @default ['Login', 'Signup', 'ForgotPassword', 'ResetPassword', 'AuthCallback']
23
23
  */
24
24
  noAuthRoutes?: string[]
25
25
 
@@ -77,7 +77,7 @@ export interface NormalizedRedirectConfig extends Required<Omit<RedirectConfig,
77
77
  export const DEFAULT_REDIRECT_CONFIG: NormalizedRedirectConfig = {
78
78
  queryKey: 'redirect',
79
79
  fallback: '/',
80
- noAuthRoutes: ['Login', 'Signup', 'ForgotPassword', 'ResetPassword', 'Callback'],
80
+ noAuthRoutes: ['Login', 'Signup', 'ForgotPassword', 'ResetPassword', 'AuthCallback'],
81
81
  authenticatedRedirect: '/',
82
82
  loginRoute: 'Login',
83
83
  authMetaKey: 'auth',
package/src/useAuth.ts CHANGED
@@ -175,7 +175,7 @@ function setupAutoRedirect() {
175
175
  eventEmitter.on(AuthState.LOGIN, async () => {
176
176
  // Only auto-redirect if router is available
177
177
  if (!autoRedirectRouter) {
178
- console.warn('[Auth] Auto-redirect enabled but router not set. Call setAuthRouter(router) in your app setup.')
178
+ console.warn('[Auth] Auto-redirect enabled but router not set. Call auth.use(router) in your app setup.')
179
179
  return
180
180
  }
181
181