@bagelink/auth 1.7.76 → 1.7.78
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 +26 -1
- package/dist/index.cjs +44 -5
- package/dist/index.mjs +44 -5
- package/dist/types/redirect.d.ts +1 -1
- package/package.json +1 -1
- package/src/pages/Callback.vue +12 -3
- package/src/sso.ts +46 -0
- package/src/types/redirect.ts +2 -2
- package/src/useAuth.ts +1 -1
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: '
|
|
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(() =>
|
|
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,7 +1103,7 @@ 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}`);
|
|
1104
1108
|
try {
|
|
1105
1109
|
const response = await sso2.handleCallback();
|
|
@@ -1108,7 +1112,10 @@ const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
|
|
|
1108
1112
|
} else {
|
|
1109
1113
|
authResponse.value = response;
|
|
1110
1114
|
success.value = true;
|
|
1111
|
-
setTimeout(() =>
|
|
1115
|
+
setTimeout(() => {
|
|
1116
|
+
const redirectPath = typeof redirect2 === "string" ? redirect2 : "/";
|
|
1117
|
+
router2.push(redirectPath);
|
|
1118
|
+
}, timeout);
|
|
1112
1119
|
}
|
|
1113
1120
|
} catch (err) {
|
|
1114
1121
|
const errorMessage = err instanceof Error ? err.message : "Authentication failed";
|
|
@@ -1584,6 +1591,13 @@ function createSSOProvider(config) {
|
|
|
1584
1591
|
const auth = getAuthApi();
|
|
1585
1592
|
const redirectUri = options.redirectUri ?? getDefaultRedirectUri();
|
|
1586
1593
|
const state = options.state ?? generateState();
|
|
1594
|
+
if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
|
|
1595
|
+
const currentParams = queryParams();
|
|
1596
|
+
const redirectUrl = currentParams.redirect;
|
|
1597
|
+
if (redirectUrl) {
|
|
1598
|
+
sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1587
1601
|
if (typeof sessionStorage !== "undefined") {
|
|
1588
1602
|
sessionStorage.setItem(getStateKey(), state);
|
|
1589
1603
|
sessionStorage.setItem(`oauth_provider:${state}`, config.id);
|
|
@@ -1602,6 +1616,13 @@ function createSSOProvider(config) {
|
|
|
1602
1616
|
const redirectUri = options.redirectUri ?? getDefaultRedirectUri();
|
|
1603
1617
|
const state = options.state ?? generateState();
|
|
1604
1618
|
const timeout2 = options.popupTimeout ?? 9e4;
|
|
1619
|
+
if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
|
|
1620
|
+
const currentParams = queryParams();
|
|
1621
|
+
const redirectUrl = currentParams.redirect;
|
|
1622
|
+
if (redirectUrl) {
|
|
1623
|
+
sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1605
1626
|
if (typeof sessionStorage !== "undefined") {
|
|
1606
1627
|
sessionStorage.setItem(getStateKey(), state);
|
|
1607
1628
|
sessionStorage.setItem(`oauth_provider:${state}`, config.id);
|
|
@@ -1818,6 +1839,15 @@ function handleOAuthCallback() {
|
|
|
1818
1839
|
if (!provider || !isSupportedProvider(provider)) {
|
|
1819
1840
|
throw new Error("Unable to determine OAuth provider. State may have expired.");
|
|
1820
1841
|
}
|
|
1842
|
+
if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
|
|
1843
|
+
const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`);
|
|
1844
|
+
if (storedRedirect) {
|
|
1845
|
+
const url = new URL(window.location.href);
|
|
1846
|
+
url.searchParams.set("redirect", storedRedirect);
|
|
1847
|
+
window.history.replaceState({}, "", url.toString());
|
|
1848
|
+
sessionStorage.removeItem(`oauth_redirect:${state}`);
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1821
1851
|
return ssoProviders[provider].callback(code, state);
|
|
1822
1852
|
}
|
|
1823
1853
|
function handleOAuthLinkCallback() {
|
|
@@ -1829,6 +1859,15 @@ function handleOAuthLinkCallback() {
|
|
|
1829
1859
|
if (!provider || !isSupportedProvider(provider)) {
|
|
1830
1860
|
throw new Error("Unable to determine OAuth provider. State may have expired.");
|
|
1831
1861
|
}
|
|
1862
|
+
if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
|
|
1863
|
+
const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`);
|
|
1864
|
+
if (storedRedirect) {
|
|
1865
|
+
const url = new URL(window.location.href);
|
|
1866
|
+
url.searchParams.set("redirect", storedRedirect);
|
|
1867
|
+
window.history.replaceState({}, "", url.toString());
|
|
1868
|
+
sessionStorage.removeItem(`oauth_redirect:${state}`);
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1832
1871
|
return ssoProviders[provider].link(code, state);
|
|
1833
1872
|
}
|
|
1834
1873
|
var AuthState = /* @__PURE__ */ ((AuthState2) => {
|
|
@@ -1891,7 +1930,7 @@ function accountToUser(account) {
|
|
|
1891
1930
|
const DEFAULT_REDIRECT_CONFIG = {
|
|
1892
1931
|
queryKey: "redirect",
|
|
1893
1932
|
fallback: "/",
|
|
1894
|
-
noAuthRoutes: ["Login", "Signup", "ForgotPassword", "ResetPassword", "
|
|
1933
|
+
noAuthRoutes: ["Login", "Signup", "ForgotPassword", "ResetPassword", "AuthCallback"],
|
|
1895
1934
|
authenticatedRedirect: "/",
|
|
1896
1935
|
loginRoute: "Login",
|
|
1897
1936
|
authMetaKey: "auth",
|
|
@@ -2019,7 +2058,7 @@ function setupAutoRedirect() {
|
|
|
2019
2058
|
if (!eventEmitter || !redirectConfig) return;
|
|
2020
2059
|
eventEmitter.on(AuthState.LOGIN, async () => {
|
|
2021
2060
|
if (!autoRedirectRouter) {
|
|
2022
|
-
console.warn("[Auth] Auto-redirect enabled but router not set. Call
|
|
2061
|
+
console.warn("[Auth] Auto-redirect enabled but router not set. Call auth.use(router) in your app setup.");
|
|
2023
2062
|
return;
|
|
2024
2063
|
}
|
|
2025
2064
|
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(() =>
|
|
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,7 +1101,7 @@ 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}`);
|
|
1102
1106
|
try {
|
|
1103
1107
|
const response = await sso2.handleCallback();
|
|
@@ -1106,7 +1110,10 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
|
|
|
1106
1110
|
} else {
|
|
1107
1111
|
authResponse.value = response;
|
|
1108
1112
|
success.value = true;
|
|
1109
|
-
setTimeout(() =>
|
|
1113
|
+
setTimeout(() => {
|
|
1114
|
+
const redirectPath = typeof redirect2 === "string" ? redirect2 : "/";
|
|
1115
|
+
router2.push(redirectPath);
|
|
1116
|
+
}, timeout);
|
|
1110
1117
|
}
|
|
1111
1118
|
} catch (err) {
|
|
1112
1119
|
const errorMessage = err instanceof Error ? err.message : "Authentication failed";
|
|
@@ -1582,6 +1589,13 @@ function createSSOProvider(config) {
|
|
|
1582
1589
|
const auth = getAuthApi();
|
|
1583
1590
|
const redirectUri = options.redirectUri ?? getDefaultRedirectUri();
|
|
1584
1591
|
const state = options.state ?? generateState();
|
|
1592
|
+
if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
|
|
1593
|
+
const currentParams = queryParams();
|
|
1594
|
+
const redirectUrl = currentParams.redirect;
|
|
1595
|
+
if (redirectUrl) {
|
|
1596
|
+
sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1585
1599
|
if (typeof sessionStorage !== "undefined") {
|
|
1586
1600
|
sessionStorage.setItem(getStateKey(), state);
|
|
1587
1601
|
sessionStorage.setItem(`oauth_provider:${state}`, config.id);
|
|
@@ -1600,6 +1614,13 @@ function createSSOProvider(config) {
|
|
|
1600
1614
|
const redirectUri = options.redirectUri ?? getDefaultRedirectUri();
|
|
1601
1615
|
const state = options.state ?? generateState();
|
|
1602
1616
|
const timeout2 = options.popupTimeout ?? 9e4;
|
|
1617
|
+
if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
|
|
1618
|
+
const currentParams = queryParams();
|
|
1619
|
+
const redirectUrl = currentParams.redirect;
|
|
1620
|
+
if (redirectUrl) {
|
|
1621
|
+
sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl);
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1603
1624
|
if (typeof sessionStorage !== "undefined") {
|
|
1604
1625
|
sessionStorage.setItem(getStateKey(), state);
|
|
1605
1626
|
sessionStorage.setItem(`oauth_provider:${state}`, config.id);
|
|
@@ -1816,6 +1837,15 @@ function handleOAuthCallback() {
|
|
|
1816
1837
|
if (!provider || !isSupportedProvider(provider)) {
|
|
1817
1838
|
throw new Error("Unable to determine OAuth provider. State may have expired.");
|
|
1818
1839
|
}
|
|
1840
|
+
if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
|
|
1841
|
+
const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`);
|
|
1842
|
+
if (storedRedirect) {
|
|
1843
|
+
const url = new URL(window.location.href);
|
|
1844
|
+
url.searchParams.set("redirect", storedRedirect);
|
|
1845
|
+
window.history.replaceState({}, "", url.toString());
|
|
1846
|
+
sessionStorage.removeItem(`oauth_redirect:${state}`);
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1819
1849
|
return ssoProviders[provider].callback(code, state);
|
|
1820
1850
|
}
|
|
1821
1851
|
function handleOAuthLinkCallback() {
|
|
@@ -1827,6 +1857,15 @@ function handleOAuthLinkCallback() {
|
|
|
1827
1857
|
if (!provider || !isSupportedProvider(provider)) {
|
|
1828
1858
|
throw new Error("Unable to determine OAuth provider. State may have expired.");
|
|
1829
1859
|
}
|
|
1860
|
+
if (typeof window !== "undefined" && typeof sessionStorage !== "undefined") {
|
|
1861
|
+
const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`);
|
|
1862
|
+
if (storedRedirect) {
|
|
1863
|
+
const url = new URL(window.location.href);
|
|
1864
|
+
url.searchParams.set("redirect", storedRedirect);
|
|
1865
|
+
window.history.replaceState({}, "", url.toString());
|
|
1866
|
+
sessionStorage.removeItem(`oauth_redirect:${state}`);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1830
1869
|
return ssoProviders[provider].link(code, state);
|
|
1831
1870
|
}
|
|
1832
1871
|
var AuthState = /* @__PURE__ */ ((AuthState2) => {
|
|
@@ -1889,7 +1928,7 @@ function accountToUser(account) {
|
|
|
1889
1928
|
const DEFAULT_REDIRECT_CONFIG = {
|
|
1890
1929
|
queryKey: "redirect",
|
|
1891
1930
|
fallback: "/",
|
|
1892
|
-
noAuthRoutes: ["Login", "Signup", "ForgotPassword", "ResetPassword", "
|
|
1931
|
+
noAuthRoutes: ["Login", "Signup", "ForgotPassword", "ResetPassword", "AuthCallback"],
|
|
1893
1932
|
authenticatedRedirect: "/",
|
|
1894
1933
|
loginRoute: "Login",
|
|
1895
1934
|
authMetaKey: "auth",
|
|
@@ -2017,7 +2056,7 @@ function setupAutoRedirect() {
|
|
|
2017
2056
|
if (!eventEmitter || !redirectConfig) return;
|
|
2018
2057
|
eventEmitter.on(AuthState.LOGIN, async () => {
|
|
2019
2058
|
if (!autoRedirectRouter) {
|
|
2020
|
-
console.warn("[Auth] Auto-redirect enabled but router not set. Call
|
|
2059
|
+
console.warn("[Auth] Auto-redirect enabled but router not set. Call auth.use(router) in your app setup.");
|
|
2021
2060
|
return;
|
|
2022
2061
|
}
|
|
2023
2062
|
const { performRedirect: performRedirect2 } = await Promise.resolve().then(() => redirect);
|
package/dist/types/redirect.d.ts
CHANGED
|
@@ -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', '
|
|
19
|
+
* @default ['Login', 'Signup', 'ForgotPassword', 'ResetPassword', 'AuthCallback']
|
|
20
20
|
*/
|
|
21
21
|
noAuthRoutes?: string[];
|
|
22
22
|
/**
|
package/package.json
CHANGED
package/src/pages/Callback.vue
CHANGED
|
@@ -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(() =>
|
|
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,7 +43,7 @@ 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
|
|
44
48
|
|
|
45
49
|
try {
|
|
@@ -49,7 +53,12 @@ async function handleCallback() {
|
|
|
49
53
|
} else {
|
|
50
54
|
authResponse.value = response
|
|
51
55
|
success.value = true
|
|
52
|
-
|
|
56
|
+
// Auto-redirect will handle navigation, but fallback to manual redirect
|
|
57
|
+
// if auto-redirect is disabled or router not connected
|
|
58
|
+
setTimeout(() => {
|
|
59
|
+
const redirectPath = typeof redirect === 'string' ? redirect : '/'
|
|
60
|
+
router.push(redirectPath)
|
|
61
|
+
}, timeout)
|
|
53
62
|
}
|
|
54
63
|
} catch (err: unknown) {
|
|
55
64
|
const errorMessage = err instanceof Error ? err.message : 'Authentication failed'
|
package/src/sso.ts
CHANGED
|
@@ -314,6 +314,16 @@ 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
|
+
sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl)
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
317
327
|
// Store state AND provider in sessionStorage for verification
|
|
318
328
|
if (typeof sessionStorage !== 'undefined') {
|
|
319
329
|
sessionStorage.setItem(getStateKey(), state)
|
|
@@ -338,6 +348,16 @@ function createSSOProvider(config: SSOProviderConfig): SSOProviderInstance {
|
|
|
338
348
|
const state = options.state ?? generateState()
|
|
339
349
|
const timeout = options.popupTimeout ?? 90000
|
|
340
350
|
|
|
351
|
+
// Preserve redirect URL from current location (for popup flow too)
|
|
352
|
+
if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {
|
|
353
|
+
const currentParams = queryParams()
|
|
354
|
+
const redirectUrl = currentParams.redirect
|
|
355
|
+
if (redirectUrl) {
|
|
356
|
+
// Store redirect URL to restore after OAuth callback
|
|
357
|
+
sessionStorage.setItem(`oauth_redirect:${state}`, redirectUrl)
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
341
361
|
// Store state AND provider in sessionStorage for verification
|
|
342
362
|
if (typeof sessionStorage !== 'undefined') {
|
|
343
363
|
sessionStorage.setItem(getStateKey(), state)
|
|
@@ -615,6 +635,19 @@ function handleOAuthCallback(): Promise<AuthenticationResponse | null> {
|
|
|
615
635
|
throw new Error('Unable to determine OAuth provider. State may have expired.')
|
|
616
636
|
}
|
|
617
637
|
|
|
638
|
+
// Restore redirect URL to current location if it was stored
|
|
639
|
+
if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {
|
|
640
|
+
const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`)
|
|
641
|
+
if (storedRedirect) {
|
|
642
|
+
// Add redirect param back to URL so auto-redirect can pick it up
|
|
643
|
+
const url = new URL(window.location.href)
|
|
644
|
+
url.searchParams.set('redirect', storedRedirect)
|
|
645
|
+
window.history.replaceState({}, '', url.toString())
|
|
646
|
+
// Clean up
|
|
647
|
+
sessionStorage.removeItem(`oauth_redirect:${state}`)
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
618
651
|
return ssoProviders[provider].callback(code, state)
|
|
619
652
|
}
|
|
620
653
|
|
|
@@ -636,5 +669,18 @@ function handleOAuthLinkCallback(): Promise<void> {
|
|
|
636
669
|
throw new Error('Unable to determine OAuth provider. State may have expired.')
|
|
637
670
|
}
|
|
638
671
|
|
|
672
|
+
// Restore redirect URL to current location if it was stored
|
|
673
|
+
if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {
|
|
674
|
+
const storedRedirect = sessionStorage.getItem(`oauth_redirect:${state}`)
|
|
675
|
+
if (storedRedirect) {
|
|
676
|
+
// Add redirect param back to URL
|
|
677
|
+
const url = new URL(window.location.href)
|
|
678
|
+
url.searchParams.set('redirect', storedRedirect)
|
|
679
|
+
window.history.replaceState({}, '', url.toString())
|
|
680
|
+
// Clean up
|
|
681
|
+
sessionStorage.removeItem(`oauth_redirect:${state}`)
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
639
685
|
return ssoProviders[provider].link(code, state)
|
|
640
686
|
}
|
package/src/types/redirect.ts
CHANGED
|
@@ -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', '
|
|
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', '
|
|
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
|
|
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
|
|