@bagelink/auth 1.7.74 → 1.7.76
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 +66 -13
- package/dist/index.cjs +110 -23
- package/dist/index.mjs +110 -23
- package/dist/router.d.ts +15 -1
- package/dist/useAuth.d.ts +46 -12
- package/package.json +1 -1
- package/src/router.ts +44 -1
- package/src/useAuth.ts +71 -15
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ npm install @bagelink/auth
|
|
|
25
25
|
```typescript
|
|
26
26
|
// main.ts
|
|
27
27
|
import { createApp } from 'vue'
|
|
28
|
-
import { createAuth
|
|
28
|
+
import { createAuth } from '@bagelink/auth'
|
|
29
29
|
import router from './router'
|
|
30
30
|
|
|
31
31
|
const auth = createAuth({
|
|
@@ -37,11 +37,8 @@ const auth = createAuth({
|
|
|
37
37
|
}
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
// Connect router
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// Install auth guard
|
|
44
|
-
router.beforeEach(authGuard())
|
|
40
|
+
// Connect router (automatically sets up auth guard)
|
|
41
|
+
auth.use(router)
|
|
45
42
|
|
|
46
43
|
const app = createApp(App)
|
|
47
44
|
app.use(router)
|
|
@@ -167,22 +164,78 @@ Returns auth composable with:
|
|
|
167
164
|
}
|
|
168
165
|
```
|
|
169
166
|
|
|
170
|
-
###
|
|
167
|
+
### Custom Guard Composition
|
|
168
|
+
|
|
169
|
+
For multi-tenant apps or advanced permission logic, disable the auto-guard and compose your own:
|
|
171
170
|
|
|
172
|
-
|
|
171
|
+
#### Option 1: Using `composeGuards` utility (recommended)
|
|
173
172
|
|
|
174
173
|
```typescript
|
|
175
|
-
|
|
174
|
+
import { composeGuards } from '@bagelink/auth'
|
|
175
|
+
|
|
176
|
+
// Disable auto-guard
|
|
177
|
+
auth.use(router, { guard: false })
|
|
178
|
+
|
|
179
|
+
// Custom org access guard
|
|
180
|
+
const orgAccessGuard = () => async (to, from, next) => {
|
|
181
|
+
if (to.meta.requiresOrg) {
|
|
182
|
+
const hasAccess = await checkOrgAccess(to.params.orgId)
|
|
183
|
+
if (!hasAccess) return next('/no-access')
|
|
184
|
+
}
|
|
185
|
+
next()
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Compose all guards in sequence
|
|
189
|
+
router.beforeEach(composeGuards([
|
|
190
|
+
auth.routerGuard(), // Auth first
|
|
191
|
+
orgAccessGuard(), // Then org check
|
|
192
|
+
]))
|
|
176
193
|
```
|
|
177
194
|
|
|
178
|
-
|
|
195
|
+
#### Option 2: Multiple `beforeEach` calls
|
|
179
196
|
|
|
180
|
-
|
|
197
|
+
```typescript
|
|
198
|
+
auth.use(router, { guard: false })
|
|
181
199
|
|
|
182
|
-
|
|
200
|
+
// Guards run in order they're registered
|
|
201
|
+
router.beforeEach(auth.routerGuard())
|
|
202
|
+
|
|
203
|
+
router.beforeEach(async (to, from, next) => {
|
|
204
|
+
// Custom org/tenant check
|
|
205
|
+
if (to.meta.requiresOrg && !await checkOrgAccess(to.params.orgId)) {
|
|
206
|
+
return next('/no-access')
|
|
207
|
+
}
|
|
208
|
+
next()
|
|
209
|
+
})
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
#### Option 3: Manual composition
|
|
183
213
|
|
|
184
214
|
```typescript
|
|
185
|
-
|
|
215
|
+
auth.use(router, { guard: false })
|
|
216
|
+
|
|
217
|
+
router.beforeEach(async (to, from, next) => {
|
|
218
|
+
// Run auth guard first
|
|
219
|
+
const authPassed = await new Promise<boolean>((resolve) => {
|
|
220
|
+
auth.routerGuard()(to, from, (result?: any) => {
|
|
221
|
+
if (result !== undefined) {
|
|
222
|
+
next(result)
|
|
223
|
+
resolve(false)
|
|
224
|
+
} else {
|
|
225
|
+
resolve(true)
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
if (!authPassed) return
|
|
231
|
+
|
|
232
|
+
// Your custom logic
|
|
233
|
+
if (to.meta.requiresOrg && !await checkOrgAccess(to.params.orgId)) {
|
|
234
|
+
return next('/no-access')
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
next()
|
|
238
|
+
})
|
|
186
239
|
```
|
|
187
240
|
|
|
188
241
|
## Components
|
package/dist/index.cjs
CHANGED
|
@@ -1079,7 +1079,7 @@ const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
|
|
|
1079
1079
|
const authResponse = vue.ref(null);
|
|
1080
1080
|
const { sso: sso2, user, accountInfo: accountInfo2 } = useAuth();
|
|
1081
1081
|
const route = vueRouter.useRoute();
|
|
1082
|
-
const
|
|
1082
|
+
const router2 = vueRouter.useRouter();
|
|
1083
1083
|
const providerInfo = vue.computed(() => {
|
|
1084
1084
|
if (provider.value === null) return null;
|
|
1085
1085
|
return providers[provider.value];
|
|
@@ -1089,7 +1089,7 @@ const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
|
|
|
1089
1089
|
try {
|
|
1090
1090
|
await sso2.handleLinkCallback();
|
|
1091
1091
|
success.value = true;
|
|
1092
|
-
setTimeout(() =>
|
|
1092
|
+
setTimeout(() => router2.push("/"), timeout);
|
|
1093
1093
|
} catch (err) {
|
|
1094
1094
|
const errorMessage = err instanceof Error ? err.message : "Failed to link account";
|
|
1095
1095
|
error.value = errorMessage;
|
|
@@ -1108,7 +1108,7 @@ const _sfc_main$4 = /* @__PURE__ */ vue.defineComponent({
|
|
|
1108
1108
|
} else {
|
|
1109
1109
|
authResponse.value = response;
|
|
1110
1110
|
success.value = true;
|
|
1111
|
-
setTimeout(() =>
|
|
1111
|
+
setTimeout(() => router2.push("/"), timeout);
|
|
1112
1112
|
}
|
|
1113
1113
|
} catch (err) {
|
|
1114
1114
|
const errorMessage = err instanceof Error ? err.message : "Authentication failed";
|
|
@@ -1239,10 +1239,10 @@ const _sfc_main$3 = /* @__PURE__ */ vue.defineComponent({
|
|
|
1239
1239
|
cardShadow: { type: Boolean, default: true }
|
|
1240
1240
|
},
|
|
1241
1241
|
setup(__props) {
|
|
1242
|
-
const
|
|
1242
|
+
const router2 = vueRouter.useRouter();
|
|
1243
1243
|
function switchForm(form) {
|
|
1244
1244
|
if (form === "login") {
|
|
1245
|
-
|
|
1245
|
+
router2.push("/login");
|
|
1246
1246
|
}
|
|
1247
1247
|
}
|
|
1248
1248
|
return (_ctx, _cache) => {
|
|
@@ -1283,12 +1283,12 @@ const _sfc_main$2 = /* @__PURE__ */ vue.defineComponent({
|
|
|
1283
1283
|
cardShadow: { type: Boolean, default: true }
|
|
1284
1284
|
},
|
|
1285
1285
|
setup(__props) {
|
|
1286
|
-
const
|
|
1286
|
+
const router2 = vueRouter.useRouter();
|
|
1287
1287
|
function switchForm(form) {
|
|
1288
1288
|
if (form === "signup") {
|
|
1289
|
-
|
|
1289
|
+
router2.push("/signup");
|
|
1290
1290
|
} else if (form === "forgot-password") {
|
|
1291
|
-
|
|
1291
|
+
router2.push("/forgot-password");
|
|
1292
1292
|
}
|
|
1293
1293
|
}
|
|
1294
1294
|
return (_ctx, _cache) => {
|
|
@@ -1329,12 +1329,12 @@ const _sfc_main$1 = /* @__PURE__ */ vue.defineComponent({
|
|
|
1329
1329
|
cardShadow: { type: Boolean, default: true }
|
|
1330
1330
|
},
|
|
1331
1331
|
setup(__props) {
|
|
1332
|
-
const
|
|
1332
|
+
const router2 = vueRouter.useRouter();
|
|
1333
1333
|
const route = vueRouter.useRoute();
|
|
1334
1334
|
const token = vue.computed(() => route.query.token);
|
|
1335
1335
|
function switchForm(form) {
|
|
1336
1336
|
if (form === "login") {
|
|
1337
|
-
|
|
1337
|
+
router2.push("/login");
|
|
1338
1338
|
}
|
|
1339
1339
|
}
|
|
1340
1340
|
return (_ctx, _cache) => {
|
|
@@ -1366,10 +1366,10 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
1366
1366
|
cardShadow: { type: Boolean, default: true }
|
|
1367
1367
|
},
|
|
1368
1368
|
setup(__props) {
|
|
1369
|
-
const
|
|
1369
|
+
const router2 = vueRouter.useRouter();
|
|
1370
1370
|
function switchForm(form) {
|
|
1371
1371
|
if (form === "login") {
|
|
1372
|
-
|
|
1372
|
+
router2.push("/login");
|
|
1373
1373
|
}
|
|
1374
1374
|
}
|
|
1375
1375
|
return (_ctx, _cache) => {
|
|
@@ -1391,8 +1391,8 @@ const _sfc_main = /* @__PURE__ */ vue.defineComponent({
|
|
|
1391
1391
|
};
|
|
1392
1392
|
}
|
|
1393
1393
|
});
|
|
1394
|
-
function getRedirectUrl(
|
|
1395
|
-
const redirect2 =
|
|
1394
|
+
function getRedirectUrl(router2, config) {
|
|
1395
|
+
const redirect2 = router2.currentRoute.value.query[config.queryKey];
|
|
1396
1396
|
return redirect2 || config.fallback;
|
|
1397
1397
|
}
|
|
1398
1398
|
function isValidRedirect(redirectUrl, allowedPaths) {
|
|
@@ -1416,14 +1416,14 @@ function isValidRedirect(redirectUrl, allowedPaths) {
|
|
|
1416
1416
|
}
|
|
1417
1417
|
return true;
|
|
1418
1418
|
}
|
|
1419
|
-
async function performRedirect(
|
|
1420
|
-
const redirect2 = getRedirectUrl(
|
|
1419
|
+
async function performRedirect(router2, config) {
|
|
1420
|
+
const redirect2 = getRedirectUrl(router2, config);
|
|
1421
1421
|
if (redirect2 !== config.fallback && !isValidRedirect(redirect2, config.allowedPaths)) {
|
|
1422
1422
|
console.warn("[Auth] Invalid redirect URL detected, using fallback:", redirect2);
|
|
1423
|
-
await
|
|
1423
|
+
await router2.push(config.fallback);
|
|
1424
1424
|
return;
|
|
1425
1425
|
}
|
|
1426
|
-
await
|
|
1426
|
+
await router2.push(redirect2);
|
|
1427
1427
|
}
|
|
1428
1428
|
function buildLoginQuery(currentPath, config) {
|
|
1429
1429
|
if (!config.preserveRedirect) {
|
|
@@ -1908,10 +1908,8 @@ let authApi = null;
|
|
|
1908
1908
|
let eventEmitter = null;
|
|
1909
1909
|
let redirectConfig = null;
|
|
1910
1910
|
let autoRedirectRouter = null;
|
|
1911
|
+
let cachedAuthGuard = null;
|
|
1911
1912
|
const accountInfo = vue.ref(null);
|
|
1912
|
-
function setAuthRouter(router) {
|
|
1913
|
-
autoRedirectRouter = router;
|
|
1914
|
-
}
|
|
1915
1913
|
function getRedirectConfig() {
|
|
1916
1914
|
if (!redirectConfig) {
|
|
1917
1915
|
throw new Error("Redirect config not initialized. Did you call createAuth with redirect config?");
|
|
@@ -1948,6 +1946,69 @@ function createAuth(params) {
|
|
|
1948
1946
|
eventEmitter.removeAllListeners(event);
|
|
1949
1947
|
}
|
|
1950
1948
|
},
|
|
1949
|
+
/**
|
|
1950
|
+
* Connect external dependencies like Vue Router
|
|
1951
|
+
* Automatically sets up router guard when router is provided
|
|
1952
|
+
* @param dependency - Vue Router instance or other plugins
|
|
1953
|
+
* @param options - Configuration options
|
|
1954
|
+
* @param options.guard - Whether to automatically set up auth guard (default: true)
|
|
1955
|
+
* @example
|
|
1956
|
+
* ```ts
|
|
1957
|
+
* // Auto setup (default)
|
|
1958
|
+
* auth.use(router)
|
|
1959
|
+
*
|
|
1960
|
+
* // Manual guard control (for custom composition)
|
|
1961
|
+
* auth.use(router, { guard: false })
|
|
1962
|
+
* router.beforeEach(async (to, from, next) => {
|
|
1963
|
+
* // Custom logic first
|
|
1964
|
+
* if (!hasOrgAccess(to)) return next('/no-access')
|
|
1965
|
+
* // Then run auth guard
|
|
1966
|
+
* return auth.routerGuard()(to, from, next)
|
|
1967
|
+
* })
|
|
1968
|
+
* ```
|
|
1969
|
+
*/
|
|
1970
|
+
use(dependency, options = {}) {
|
|
1971
|
+
const { guard = true } = options;
|
|
1972
|
+
if (dependency && (dependency.beforeEach || dependency.push || dependency.currentRoute)) {
|
|
1973
|
+
autoRedirectRouter = dependency;
|
|
1974
|
+
if (guard) {
|
|
1975
|
+
dependency.beforeEach(authInstance.routerGuard());
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
return authInstance;
|
|
1979
|
+
},
|
|
1980
|
+
/**
|
|
1981
|
+
* Create a Vue Router navigation guard for authentication
|
|
1982
|
+
* Protects routes requiring authentication and handles redirect logic
|
|
1983
|
+
* Note: Automatically called by auth.use(router), only use directly for custom setups
|
|
1984
|
+
* @example
|
|
1985
|
+
* ```ts
|
|
1986
|
+
* // Automatic (recommended)
|
|
1987
|
+
* auth.use(router)
|
|
1988
|
+
*
|
|
1989
|
+
* // Manual (for custom setups)
|
|
1990
|
+
* router.beforeEach(auth.routerGuard())
|
|
1991
|
+
* ```
|
|
1992
|
+
*/
|
|
1993
|
+
routerGuard() {
|
|
1994
|
+
if (cachedAuthGuard === null) {
|
|
1995
|
+
cachedAuthGuard = async (to, from, next) => {
|
|
1996
|
+
const { authGuard: authGuard2 } = await Promise.resolve().then(() => router);
|
|
1997
|
+
const guard = authGuard2();
|
|
1998
|
+
cachedAuthGuard = guard;
|
|
1999
|
+
return guard(to, from, next);
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
return cachedAuthGuard;
|
|
2003
|
+
},
|
|
2004
|
+
/**
|
|
2005
|
+
* Vue plugin install method
|
|
2006
|
+
* Makes auth available globally as $auth
|
|
2007
|
+
* @example
|
|
2008
|
+
* ```ts
|
|
2009
|
+
* app.use(auth)
|
|
2010
|
+
* ```
|
|
2011
|
+
*/
|
|
1951
2012
|
install(app) {
|
|
1952
2013
|
app.config.globalProperties.$auth = useAuth();
|
|
1953
2014
|
}
|
|
@@ -2218,7 +2279,6 @@ const useAuth$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePro
|
|
|
2218
2279
|
__proto__: null,
|
|
2219
2280
|
createAuth,
|
|
2220
2281
|
getRedirectConfig,
|
|
2221
|
-
setAuthRouter,
|
|
2222
2282
|
useAuth
|
|
2223
2283
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
2224
2284
|
let authInitialized = false;
|
|
@@ -2256,6 +2316,33 @@ function authGuard() {
|
|
|
2256
2316
|
}
|
|
2257
2317
|
};
|
|
2258
2318
|
}
|
|
2319
|
+
function composeGuards(guards) {
|
|
2320
|
+
return async (to, from, next) => {
|
|
2321
|
+
let guardIndex = 0;
|
|
2322
|
+
const runNextGuard = async () => {
|
|
2323
|
+
if (guardIndex >= guards.length) {
|
|
2324
|
+
next();
|
|
2325
|
+
return;
|
|
2326
|
+
}
|
|
2327
|
+
const guard = guards[guardIndex];
|
|
2328
|
+
guardIndex++;
|
|
2329
|
+
await guard(to, from, (result) => {
|
|
2330
|
+
if (result !== void 0) {
|
|
2331
|
+
next(result);
|
|
2332
|
+
} else {
|
|
2333
|
+
runNextGuard();
|
|
2334
|
+
}
|
|
2335
|
+
});
|
|
2336
|
+
};
|
|
2337
|
+
await runNextGuard();
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2341
|
+
__proto__: null,
|
|
2342
|
+
authGuard,
|
|
2343
|
+
composeGuards,
|
|
2344
|
+
resetAuthState
|
|
2345
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
2259
2346
|
function createAuthRoutes(config = {}) {
|
|
2260
2347
|
const {
|
|
2261
2348
|
basePath = "",
|
|
@@ -2342,6 +2429,7 @@ exports.StateMismatchError = StateMismatchError;
|
|
|
2342
2429
|
exports.accountToUser = accountToUser;
|
|
2343
2430
|
exports.authGuard = authGuard;
|
|
2344
2431
|
exports.buildLoginQuery = buildLoginQuery;
|
|
2432
|
+
exports.composeGuards = composeGuards;
|
|
2345
2433
|
exports.createAuth = createAuth;
|
|
2346
2434
|
exports.createAuthGuard = createAuthGuard;
|
|
2347
2435
|
exports.createAuthRoutes = createAuthRoutes;
|
|
@@ -2356,7 +2444,6 @@ exports.performRedirect = performRedirect;
|
|
|
2356
2444
|
exports.providers = providers;
|
|
2357
2445
|
exports.resetAuthState = resetAuthState;
|
|
2358
2446
|
exports.setAuthContext = setAuthContext;
|
|
2359
|
-
exports.setAuthRouter = setAuthRouter;
|
|
2360
2447
|
exports.sso = sso;
|
|
2361
2448
|
exports.ssoProvidersList = ssoProvidersList;
|
|
2362
2449
|
exports.useAuth = useAuth;
|
package/dist/index.mjs
CHANGED
|
@@ -1077,7 +1077,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
|
|
|
1077
1077
|
const authResponse = ref(null);
|
|
1078
1078
|
const { sso: sso2, user, accountInfo: accountInfo2 } = useAuth();
|
|
1079
1079
|
const route = useRoute();
|
|
1080
|
-
const
|
|
1080
|
+
const router2 = useRouter();
|
|
1081
1081
|
const providerInfo = computed(() => {
|
|
1082
1082
|
if (provider.value === null) return null;
|
|
1083
1083
|
return providers[provider.value];
|
|
@@ -1087,7 +1087,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
|
|
|
1087
1087
|
try {
|
|
1088
1088
|
await sso2.handleLinkCallback();
|
|
1089
1089
|
success.value = true;
|
|
1090
|
-
setTimeout(() =>
|
|
1090
|
+
setTimeout(() => router2.push("/"), timeout);
|
|
1091
1091
|
} catch (err) {
|
|
1092
1092
|
const errorMessage = err instanceof Error ? err.message : "Failed to link account";
|
|
1093
1093
|
error.value = errorMessage;
|
|
@@ -1106,7 +1106,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
|
|
|
1106
1106
|
} else {
|
|
1107
1107
|
authResponse.value = response;
|
|
1108
1108
|
success.value = true;
|
|
1109
|
-
setTimeout(() =>
|
|
1109
|
+
setTimeout(() => router2.push("/"), timeout);
|
|
1110
1110
|
}
|
|
1111
1111
|
} catch (err) {
|
|
1112
1112
|
const errorMessage = err instanceof Error ? err.message : "Authentication failed";
|
|
@@ -1237,10 +1237,10 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
|
|
|
1237
1237
|
cardShadow: { type: Boolean, default: true }
|
|
1238
1238
|
},
|
|
1239
1239
|
setup(__props) {
|
|
1240
|
-
const
|
|
1240
|
+
const router2 = useRouter();
|
|
1241
1241
|
function switchForm(form) {
|
|
1242
1242
|
if (form === "login") {
|
|
1243
|
-
|
|
1243
|
+
router2.push("/login");
|
|
1244
1244
|
}
|
|
1245
1245
|
}
|
|
1246
1246
|
return (_ctx, _cache) => {
|
|
@@ -1281,12 +1281,12 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
|
|
|
1281
1281
|
cardShadow: { type: Boolean, default: true }
|
|
1282
1282
|
},
|
|
1283
1283
|
setup(__props) {
|
|
1284
|
-
const
|
|
1284
|
+
const router2 = useRouter();
|
|
1285
1285
|
function switchForm(form) {
|
|
1286
1286
|
if (form === "signup") {
|
|
1287
|
-
|
|
1287
|
+
router2.push("/signup");
|
|
1288
1288
|
} else if (form === "forgot-password") {
|
|
1289
|
-
|
|
1289
|
+
router2.push("/forgot-password");
|
|
1290
1290
|
}
|
|
1291
1291
|
}
|
|
1292
1292
|
return (_ctx, _cache) => {
|
|
@@ -1327,12 +1327,12 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
|
|
|
1327
1327
|
cardShadow: { type: Boolean, default: true }
|
|
1328
1328
|
},
|
|
1329
1329
|
setup(__props) {
|
|
1330
|
-
const
|
|
1330
|
+
const router2 = useRouter();
|
|
1331
1331
|
const route = useRoute();
|
|
1332
1332
|
const token = computed(() => route.query.token);
|
|
1333
1333
|
function switchForm(form) {
|
|
1334
1334
|
if (form === "login") {
|
|
1335
|
-
|
|
1335
|
+
router2.push("/login");
|
|
1336
1336
|
}
|
|
1337
1337
|
}
|
|
1338
1338
|
return (_ctx, _cache) => {
|
|
@@ -1364,10 +1364,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1364
1364
|
cardShadow: { type: Boolean, default: true }
|
|
1365
1365
|
},
|
|
1366
1366
|
setup(__props) {
|
|
1367
|
-
const
|
|
1367
|
+
const router2 = useRouter();
|
|
1368
1368
|
function switchForm(form) {
|
|
1369
1369
|
if (form === "login") {
|
|
1370
|
-
|
|
1370
|
+
router2.push("/login");
|
|
1371
1371
|
}
|
|
1372
1372
|
}
|
|
1373
1373
|
return (_ctx, _cache) => {
|
|
@@ -1389,8 +1389,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
1389
1389
|
};
|
|
1390
1390
|
}
|
|
1391
1391
|
});
|
|
1392
|
-
function getRedirectUrl(
|
|
1393
|
-
const redirect2 =
|
|
1392
|
+
function getRedirectUrl(router2, config) {
|
|
1393
|
+
const redirect2 = router2.currentRoute.value.query[config.queryKey];
|
|
1394
1394
|
return redirect2 || config.fallback;
|
|
1395
1395
|
}
|
|
1396
1396
|
function isValidRedirect(redirectUrl, allowedPaths) {
|
|
@@ -1414,14 +1414,14 @@ function isValidRedirect(redirectUrl, allowedPaths) {
|
|
|
1414
1414
|
}
|
|
1415
1415
|
return true;
|
|
1416
1416
|
}
|
|
1417
|
-
async function performRedirect(
|
|
1418
|
-
const redirect2 = getRedirectUrl(
|
|
1417
|
+
async function performRedirect(router2, config) {
|
|
1418
|
+
const redirect2 = getRedirectUrl(router2, config);
|
|
1419
1419
|
if (redirect2 !== config.fallback && !isValidRedirect(redirect2, config.allowedPaths)) {
|
|
1420
1420
|
console.warn("[Auth] Invalid redirect URL detected, using fallback:", redirect2);
|
|
1421
|
-
await
|
|
1421
|
+
await router2.push(config.fallback);
|
|
1422
1422
|
return;
|
|
1423
1423
|
}
|
|
1424
|
-
await
|
|
1424
|
+
await router2.push(redirect2);
|
|
1425
1425
|
}
|
|
1426
1426
|
function buildLoginQuery(currentPath, config) {
|
|
1427
1427
|
if (!config.preserveRedirect) {
|
|
@@ -1906,10 +1906,8 @@ let authApi = null;
|
|
|
1906
1906
|
let eventEmitter = null;
|
|
1907
1907
|
let redirectConfig = null;
|
|
1908
1908
|
let autoRedirectRouter = null;
|
|
1909
|
+
let cachedAuthGuard = null;
|
|
1909
1910
|
const accountInfo = ref(null);
|
|
1910
|
-
function setAuthRouter(router) {
|
|
1911
|
-
autoRedirectRouter = router;
|
|
1912
|
-
}
|
|
1913
1911
|
function getRedirectConfig() {
|
|
1914
1912
|
if (!redirectConfig) {
|
|
1915
1913
|
throw new Error("Redirect config not initialized. Did you call createAuth with redirect config?");
|
|
@@ -1946,6 +1944,69 @@ function createAuth(params) {
|
|
|
1946
1944
|
eventEmitter.removeAllListeners(event);
|
|
1947
1945
|
}
|
|
1948
1946
|
},
|
|
1947
|
+
/**
|
|
1948
|
+
* Connect external dependencies like Vue Router
|
|
1949
|
+
* Automatically sets up router guard when router is provided
|
|
1950
|
+
* @param dependency - Vue Router instance or other plugins
|
|
1951
|
+
* @param options - Configuration options
|
|
1952
|
+
* @param options.guard - Whether to automatically set up auth guard (default: true)
|
|
1953
|
+
* @example
|
|
1954
|
+
* ```ts
|
|
1955
|
+
* // Auto setup (default)
|
|
1956
|
+
* auth.use(router)
|
|
1957
|
+
*
|
|
1958
|
+
* // Manual guard control (for custom composition)
|
|
1959
|
+
* auth.use(router, { guard: false })
|
|
1960
|
+
* router.beforeEach(async (to, from, next) => {
|
|
1961
|
+
* // Custom logic first
|
|
1962
|
+
* if (!hasOrgAccess(to)) return next('/no-access')
|
|
1963
|
+
* // Then run auth guard
|
|
1964
|
+
* return auth.routerGuard()(to, from, next)
|
|
1965
|
+
* })
|
|
1966
|
+
* ```
|
|
1967
|
+
*/
|
|
1968
|
+
use(dependency, options = {}) {
|
|
1969
|
+
const { guard = true } = options;
|
|
1970
|
+
if (dependency && (dependency.beforeEach || dependency.push || dependency.currentRoute)) {
|
|
1971
|
+
autoRedirectRouter = dependency;
|
|
1972
|
+
if (guard) {
|
|
1973
|
+
dependency.beforeEach(authInstance.routerGuard());
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
return authInstance;
|
|
1977
|
+
},
|
|
1978
|
+
/**
|
|
1979
|
+
* Create a Vue Router navigation guard for authentication
|
|
1980
|
+
* Protects routes requiring authentication and handles redirect logic
|
|
1981
|
+
* Note: Automatically called by auth.use(router), only use directly for custom setups
|
|
1982
|
+
* @example
|
|
1983
|
+
* ```ts
|
|
1984
|
+
* // Automatic (recommended)
|
|
1985
|
+
* auth.use(router)
|
|
1986
|
+
*
|
|
1987
|
+
* // Manual (for custom setups)
|
|
1988
|
+
* router.beforeEach(auth.routerGuard())
|
|
1989
|
+
* ```
|
|
1990
|
+
*/
|
|
1991
|
+
routerGuard() {
|
|
1992
|
+
if (cachedAuthGuard === null) {
|
|
1993
|
+
cachedAuthGuard = async (to, from, next) => {
|
|
1994
|
+
const { authGuard: authGuard2 } = await Promise.resolve().then(() => router);
|
|
1995
|
+
const guard = authGuard2();
|
|
1996
|
+
cachedAuthGuard = guard;
|
|
1997
|
+
return guard(to, from, next);
|
|
1998
|
+
};
|
|
1999
|
+
}
|
|
2000
|
+
return cachedAuthGuard;
|
|
2001
|
+
},
|
|
2002
|
+
/**
|
|
2003
|
+
* Vue plugin install method
|
|
2004
|
+
* Makes auth available globally as $auth
|
|
2005
|
+
* @example
|
|
2006
|
+
* ```ts
|
|
2007
|
+
* app.use(auth)
|
|
2008
|
+
* ```
|
|
2009
|
+
*/
|
|
1949
2010
|
install(app) {
|
|
1950
2011
|
app.config.globalProperties.$auth = useAuth();
|
|
1951
2012
|
}
|
|
@@ -2216,7 +2277,6 @@ const useAuth$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePro
|
|
|
2216
2277
|
__proto__: null,
|
|
2217
2278
|
createAuth,
|
|
2218
2279
|
getRedirectConfig,
|
|
2219
|
-
setAuthRouter,
|
|
2220
2280
|
useAuth
|
|
2221
2281
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
2222
2282
|
let authInitialized = false;
|
|
@@ -2254,6 +2314,33 @@ function authGuard() {
|
|
|
2254
2314
|
}
|
|
2255
2315
|
};
|
|
2256
2316
|
}
|
|
2317
|
+
function composeGuards(guards) {
|
|
2318
|
+
return async (to, from, next) => {
|
|
2319
|
+
let guardIndex = 0;
|
|
2320
|
+
const runNextGuard = async () => {
|
|
2321
|
+
if (guardIndex >= guards.length) {
|
|
2322
|
+
next();
|
|
2323
|
+
return;
|
|
2324
|
+
}
|
|
2325
|
+
const guard = guards[guardIndex];
|
|
2326
|
+
guardIndex++;
|
|
2327
|
+
await guard(to, from, (result) => {
|
|
2328
|
+
if (result !== void 0) {
|
|
2329
|
+
next(result);
|
|
2330
|
+
} else {
|
|
2331
|
+
runNextGuard();
|
|
2332
|
+
}
|
|
2333
|
+
});
|
|
2334
|
+
};
|
|
2335
|
+
await runNextGuard();
|
|
2336
|
+
};
|
|
2337
|
+
}
|
|
2338
|
+
const router = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2339
|
+
__proto__: null,
|
|
2340
|
+
authGuard,
|
|
2341
|
+
composeGuards,
|
|
2342
|
+
resetAuthState
|
|
2343
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
2257
2344
|
function createAuthRoutes(config = {}) {
|
|
2258
2345
|
const {
|
|
2259
2346
|
basePath = "",
|
|
@@ -2341,6 +2428,7 @@ export {
|
|
|
2341
2428
|
accountToUser,
|
|
2342
2429
|
authGuard,
|
|
2343
2430
|
buildLoginQuery,
|
|
2431
|
+
composeGuards,
|
|
2344
2432
|
createAuth,
|
|
2345
2433
|
createAuthGuard,
|
|
2346
2434
|
createAuthRoutes,
|
|
@@ -2355,7 +2443,6 @@ export {
|
|
|
2355
2443
|
providers,
|
|
2356
2444
|
resetAuthState,
|
|
2357
2445
|
setAuthContext,
|
|
2358
|
-
setAuthRouter,
|
|
2359
2446
|
sso,
|
|
2360
2447
|
ssoProvidersList,
|
|
2361
2448
|
useAuth
|
package/dist/router.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NavigationGuardNext, RouteLocationNormalized } from 'vue-router';
|
|
1
|
+
import { NavigationGuard, NavigationGuardNext, RouteLocationNormalized } from 'vue-router';
|
|
2
2
|
/**
|
|
3
3
|
* Reset auth initialization state
|
|
4
4
|
* Useful for testing or app reload scenarios
|
|
@@ -20,3 +20,17 @@ export declare function resetAuthState(): void;
|
|
|
20
20
|
* ```
|
|
21
21
|
*/
|
|
22
22
|
export declare function authGuard(): (to: RouteLocationNormalized, _from: RouteLocationNormalized, next: NavigationGuardNext) => Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Compose multiple navigation guards into one
|
|
25
|
+
* Guards are executed in order, stopping at the first one that calls next with a value
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* router.beforeEach(composeGuards([
|
|
30
|
+
* authGuard(),
|
|
31
|
+
* orgAccessGuard(),
|
|
32
|
+
* featureFlagGuard(),
|
|
33
|
+
* ]))
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function composeGuards(guards: NavigationGuard[]): NavigationGuard;
|
package/dist/useAuth.d.ts
CHANGED
|
@@ -9,18 +9,6 @@ interface InitParams {
|
|
|
9
9
|
*/
|
|
10
10
|
redirect?: RedirectConfig;
|
|
11
11
|
}
|
|
12
|
-
/**
|
|
13
|
-
* Set the router instance for auto-redirect functionality
|
|
14
|
-
* Call this in your app setup after creating the router
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* ```ts
|
|
18
|
-
* const auth = createAuth({ ... })
|
|
19
|
-
* const router = createRouter({ ... })
|
|
20
|
-
* setAuthRouter(router)
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
export declare function setAuthRouter(router: any): void;
|
|
24
12
|
/**
|
|
25
13
|
* Get the current redirect configuration
|
|
26
14
|
* Used internally by router guard
|
|
@@ -30,6 +18,52 @@ export declare function createAuth(params: InitParams): {
|
|
|
30
18
|
on<K extends AuthState>(event: K, handler: AuthEventMap[K]): void;
|
|
31
19
|
off<K extends AuthState>(event: K, handler: AuthEventMap[K]): void;
|
|
32
20
|
removeAllListeners<K extends AuthState>(event?: K): void;
|
|
21
|
+
/**
|
|
22
|
+
* Connect external dependencies like Vue Router
|
|
23
|
+
* Automatically sets up router guard when router is provided
|
|
24
|
+
* @param dependency - Vue Router instance or other plugins
|
|
25
|
+
* @param options - Configuration options
|
|
26
|
+
* @param options.guard - Whether to automatically set up auth guard (default: true)
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* // Auto setup (default)
|
|
30
|
+
* auth.use(router)
|
|
31
|
+
*
|
|
32
|
+
* // Manual guard control (for custom composition)
|
|
33
|
+
* auth.use(router, { guard: false })
|
|
34
|
+
* router.beforeEach(async (to, from, next) => {
|
|
35
|
+
* // Custom logic first
|
|
36
|
+
* if (!hasOrgAccess(to)) return next('/no-access')
|
|
37
|
+
* // Then run auth guard
|
|
38
|
+
* return auth.routerGuard()(to, from, next)
|
|
39
|
+
* })
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
use(dependency: any, options?: {
|
|
43
|
+
guard?: boolean;
|
|
44
|
+
}): /*elided*/ any;
|
|
45
|
+
/**
|
|
46
|
+
* Create a Vue Router navigation guard for authentication
|
|
47
|
+
* Protects routes requiring authentication and handles redirect logic
|
|
48
|
+
* Note: Automatically called by auth.use(router), only use directly for custom setups
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* // Automatic (recommended)
|
|
52
|
+
* auth.use(router)
|
|
53
|
+
*
|
|
54
|
+
* // Manual (for custom setups)
|
|
55
|
+
* router.beforeEach(auth.routerGuard())
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
routerGuard(): any;
|
|
59
|
+
/**
|
|
60
|
+
* Vue plugin install method
|
|
61
|
+
* Makes auth available globally as $auth
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* app.use(auth)
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
33
67
|
install(app: App): void;
|
|
34
68
|
};
|
|
35
69
|
export declare function useAuth(): {
|
package/package.json
CHANGED
package/src/router.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NavigationGuardNext, RouteLocationNormalized } from 'vue-router'
|
|
1
|
+
import type { NavigationGuard, NavigationGuardNext, RouteLocationNormalized } from 'vue-router'
|
|
2
2
|
import { buildLoginQuery } from './redirect'
|
|
3
3
|
import { useAuth, getRedirectConfig } from './useAuth'
|
|
4
4
|
|
|
@@ -84,3 +84,46 @@ export function authGuard() {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Compose multiple navigation guards into one
|
|
90
|
+
* Guards are executed in order, stopping at the first one that calls next with a value
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* router.beforeEach(composeGuards([
|
|
95
|
+
* authGuard(),
|
|
96
|
+
* orgAccessGuard(),
|
|
97
|
+
* featureFlagGuard(),
|
|
98
|
+
* ]))
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export function composeGuards(guards: NavigationGuard[]): NavigationGuard {
|
|
102
|
+
return async (to, from, next) => {
|
|
103
|
+
let guardIndex = 0
|
|
104
|
+
|
|
105
|
+
const runNextGuard = async (): Promise<void> => {
|
|
106
|
+
if (guardIndex >= guards.length) {
|
|
107
|
+
// All guards passed, allow navigation
|
|
108
|
+
next()
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const guard = guards[guardIndex]
|
|
113
|
+
guardIndex++
|
|
114
|
+
|
|
115
|
+
// Run the current guard
|
|
116
|
+
await guard(to, from, (result?: any) => {
|
|
117
|
+
if (result !== undefined) {
|
|
118
|
+
// Guard blocked or redirected, stop here
|
|
119
|
+
next(result)
|
|
120
|
+
} else {
|
|
121
|
+
// Guard passed, run next guard
|
|
122
|
+
runNextGuard()
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
await runNextGuard()
|
|
128
|
+
}
|
|
129
|
+
}
|
package/src/useAuth.ts
CHANGED
|
@@ -24,6 +24,7 @@ let authApi: AuthApi | null = null
|
|
|
24
24
|
let eventEmitter: EventEmitter | null = null
|
|
25
25
|
let redirectConfig: NormalizedRedirectConfig | null = null
|
|
26
26
|
let autoRedirectRouter: any = null // Router instance for auto-redirect
|
|
27
|
+
let cachedAuthGuard: any = null // Cached router guard
|
|
27
28
|
const accountInfo = ref<AccountInfo | null>(null)
|
|
28
29
|
|
|
29
30
|
interface InitParams {
|
|
@@ -35,21 +36,6 @@ interface InitParams {
|
|
|
35
36
|
redirect?: RedirectConfig
|
|
36
37
|
}
|
|
37
38
|
|
|
38
|
-
/**
|
|
39
|
-
* Set the router instance for auto-redirect functionality
|
|
40
|
-
* Call this in your app setup after creating the router
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```ts
|
|
44
|
-
* const auth = createAuth({ ... })
|
|
45
|
-
* const router = createRouter({ ... })
|
|
46
|
-
* setAuthRouter(router)
|
|
47
|
-
* ```
|
|
48
|
-
*/
|
|
49
|
-
export function setAuthRouter(router: any) {
|
|
50
|
-
autoRedirectRouter = router
|
|
51
|
-
}
|
|
52
|
-
|
|
53
39
|
/**
|
|
54
40
|
* Get the current redirect configuration
|
|
55
41
|
* Used internally by router guard
|
|
@@ -101,6 +87,76 @@ export function createAuth(params: InitParams) {
|
|
|
101
87
|
}
|
|
102
88
|
},
|
|
103
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Connect external dependencies like Vue Router
|
|
92
|
+
* Automatically sets up router guard when router is provided
|
|
93
|
+
* @param dependency - Vue Router instance or other plugins
|
|
94
|
+
* @param options - Configuration options
|
|
95
|
+
* @param options.guard - Whether to automatically set up auth guard (default: true)
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* // Auto setup (default)
|
|
99
|
+
* auth.use(router)
|
|
100
|
+
*
|
|
101
|
+
* // Manual guard control (for custom composition)
|
|
102
|
+
* auth.use(router, { guard: false })
|
|
103
|
+
* router.beforeEach(async (to, from, next) => {
|
|
104
|
+
* // Custom logic first
|
|
105
|
+
* if (!hasOrgAccess(to)) return next('/no-access')
|
|
106
|
+
* // Then run auth guard
|
|
107
|
+
* return auth.routerGuard()(to, from, next)
|
|
108
|
+
* })
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
use(dependency: any, options: { guard?: boolean } = {}) {
|
|
112
|
+
const { guard = true } = options
|
|
113
|
+
|
|
114
|
+
// Detect if it's a router by checking for common router properties
|
|
115
|
+
if (dependency && (dependency.beforeEach || dependency.push || dependency.currentRoute)) {
|
|
116
|
+
autoRedirectRouter = dependency
|
|
117
|
+
// Automatically set up the auth guard unless disabled
|
|
118
|
+
if (guard) {
|
|
119
|
+
dependency.beforeEach(authInstance.routerGuard())
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return authInstance
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Create a Vue Router navigation guard for authentication
|
|
127
|
+
* Protects routes requiring authentication and handles redirect logic
|
|
128
|
+
* Note: Automatically called by auth.use(router), only use directly for custom setups
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* // Automatic (recommended)
|
|
132
|
+
* auth.use(router)
|
|
133
|
+
*
|
|
134
|
+
* // Manual (for custom setups)
|
|
135
|
+
* router.beforeEach(auth.routerGuard())
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
routerGuard() {
|
|
139
|
+
// Return factory that lazily loads authGuard to avoid circular dependency
|
|
140
|
+
if (cachedAuthGuard === null) {
|
|
141
|
+
cachedAuthGuard = async (to: any, from: any, next: any) => {
|
|
142
|
+
const { authGuard } = await import('./router')
|
|
143
|
+
const guard = authGuard()
|
|
144
|
+
// Cache the actual guard for next time
|
|
145
|
+
cachedAuthGuard = guard
|
|
146
|
+
return guard(to, from, next)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return cachedAuthGuard
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Vue plugin install method
|
|
154
|
+
* Makes auth available globally as $auth
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* app.use(auth)
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
104
160
|
install(app: App) {
|
|
105
161
|
// Make auth available globally
|
|
106
162
|
app.config.globalProperties.$auth = useAuth()
|