@drmhse/authos-vue 0.2.6 → 0.2.8
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/index.d.mts +565 -524
- package/dist/index.d.ts +565 -524
- package/dist/index.js +1285 -1198
- package/dist/index.mjs +1262 -1155
- package/dist/nuxt.d.mts +29 -29
- package/dist/nuxt.d.ts +29 -29
- package/dist/nuxt.js +57 -11354
- package/dist/nuxt.mjs +55 -10080
- package/dist/useAuthOS-DEOIm_-6.mjs +47 -0
- package/dist/useAuthOS-PBWjiXpo.js +58 -0
- package/package.json +6 -6
- package/dist/chokidar-B7NTEAA6.mjs +0 -1730
- package/dist/chunk-5OCDR7QV.mjs +0 -68
- package/dist/chunk-6DZX6EAA.mjs +0 -33
- package/dist/chunk-CD2MZG7D.mjs +0 -103
- package/dist/chunk-I3MWU7CX.mjs +0 -405
- package/dist/chunk-IUIUWQYL.mjs +0 -700
- package/dist/chunk-IYGVWWRW.mjs +0 -448
- package/dist/chunk-JN6U6SKP.mjs +0 -973
- package/dist/chunk-T7GBCGRZ.mjs +0 -734
- package/dist/chunk-VVJVQ4JO.mjs +0 -15
- package/dist/chunk-YED35B36.mjs +0 -33
- package/dist/chunk-ZHH4WLMR.mjs +0 -18
- package/dist/dist-N5W7B4HY.mjs +0 -3
- package/dist/dist-XLLRDJPJ.mjs +0 -505
- package/dist/json5-XBNSJCDA.mjs +0 -3
- package/dist/jsonc-H6LEPRFY.mjs +0 -3
- package/dist/nypm-5BYDGLH7.mjs +0 -3
- package/dist/prompt-WWTBWNTY.mjs +0 -751
- package/dist/tar-A5SPYDDD.mjs +0 -3289
- package/dist/toml-QZCHCWUM.mjs +0 -3
- package/dist/utils-YSWQHENC.mjs +0 -94
- package/dist/yaml-6OXYI3W7.mjs +0 -3
package/dist/index.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// src/styles.ts
|
|
12
|
-
var AUTHOS_STYLES = `
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_useAuthOS = require("./useAuthOS-PBWjiXpo.js");
|
|
3
|
+
let vue = require("vue");
|
|
4
|
+
let _drmhse_sso_sdk = require("@drmhse/sso-sdk");
|
|
5
|
+
//#region src/styles.ts
|
|
6
|
+
/**
|
|
7
|
+
* Built-in styles for AuthOS Vue components.
|
|
8
|
+
* Provides polished default styling with CSS custom properties for theming.
|
|
9
|
+
*/
|
|
10
|
+
const AUTHOS_STYLES = `
|
|
13
11
|
/* ==========================================================================
|
|
14
12
|
AuthOS Component Styles
|
|
15
13
|
CSS Variables + Default Theme
|
|
@@ -438,1228 +436,1311 @@ var AUTHOS_STYLES = `
|
|
|
438
436
|
opacity: 0.6;
|
|
439
437
|
}
|
|
440
438
|
`;
|
|
441
|
-
|
|
439
|
+
/**
|
|
440
|
+
* Injects the AuthOS styles into the document head.
|
|
441
|
+
* Only injects once, even if called multiple times.
|
|
442
|
+
*/
|
|
443
|
+
let stylesInjected = false;
|
|
442
444
|
function injectStyles() {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
445
|
+
if (stylesInjected) return;
|
|
446
|
+
if (typeof document === "undefined") return;
|
|
447
|
+
const styleElement = document.createElement("style");
|
|
448
|
+
styleElement.setAttribute("data-authos-styles", "");
|
|
449
|
+
styleElement.textContent = AUTHOS_STYLES;
|
|
450
|
+
document.head.appendChild(styleElement);
|
|
451
|
+
stylesInjected = true;
|
|
450
452
|
}
|
|
453
|
+
/**
|
|
454
|
+
* Applies custom CSS variable overrides for theming.
|
|
455
|
+
*/
|
|
451
456
|
function applyVariables(variables) {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
457
|
+
if (typeof document === "undefined") return;
|
|
458
|
+
const root = document.documentElement;
|
|
459
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
460
|
+
const cssVar = `--authos-${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
|
|
461
|
+
root.style.setProperty(cssVar, value);
|
|
462
|
+
}
|
|
458
463
|
}
|
|
459
|
-
|
|
460
|
-
|
|
464
|
+
//#endregion
|
|
465
|
+
//#region src/plugin.ts
|
|
461
466
|
function createAuthOS(options) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
}
|
|
527
|
-
try {
|
|
528
|
-
const orgs = await client.organizations.list();
|
|
529
|
-
state.organizations = orgs;
|
|
530
|
-
if (orgs.length > 0 && !state.currentOrganization) {
|
|
531
|
-
state.currentOrganization = orgs[0];
|
|
532
|
-
}
|
|
533
|
-
} catch {
|
|
534
|
-
state.organizations = [];
|
|
535
|
-
}
|
|
536
|
-
} else {
|
|
537
|
-
state.user = null;
|
|
538
|
-
state.currentOrganization = null;
|
|
539
|
-
state.organizations = [];
|
|
540
|
-
}
|
|
541
|
-
});
|
|
542
|
-
app.provide(AUTH_OS_INJECTION_KEY, context);
|
|
543
|
-
app.config.globalProperties.$authOS = context;
|
|
544
|
-
}
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
function useAuthOS() {
|
|
548
|
-
const context = vue.inject(AUTH_OS_INJECTION_KEY);
|
|
549
|
-
if (!context) {
|
|
550
|
-
const defaultOptions = {
|
|
551
|
-
baseURL: "http://localhost:3001"
|
|
552
|
-
};
|
|
553
|
-
const defaultClient = new ssoSdk.SsoClient({
|
|
554
|
-
baseURL: defaultOptions.baseURL,
|
|
555
|
-
storage: new ssoSdk.MemoryStorage()
|
|
556
|
-
});
|
|
557
|
-
return {
|
|
558
|
-
client: defaultClient,
|
|
559
|
-
options: defaultOptions,
|
|
560
|
-
isLoading: vue.computed(() => false),
|
|
561
|
-
isAuthenticated: vue.computed(() => false)
|
|
562
|
-
};
|
|
563
|
-
}
|
|
564
|
-
const isLoading = vue.computed(() => context.state.isLoading);
|
|
565
|
-
const isAuthenticated = vue.computed(() => context.state.isAuthenticated);
|
|
566
|
-
return {
|
|
567
|
-
client: context.client,
|
|
568
|
-
options: context.options,
|
|
569
|
-
isLoading,
|
|
570
|
-
isAuthenticated
|
|
571
|
-
};
|
|
467
|
+
const getStorage = () => {
|
|
468
|
+
if (options.storage) return options.storage;
|
|
469
|
+
try {
|
|
470
|
+
if (typeof window !== "undefined" && window.localStorage) return new _drmhse_sso_sdk.BrowserStorage();
|
|
471
|
+
} catch {}
|
|
472
|
+
return new _drmhse_sso_sdk.MemoryStorage();
|
|
473
|
+
};
|
|
474
|
+
const client = new _drmhse_sso_sdk.SsoClient({
|
|
475
|
+
baseURL: options.baseURL,
|
|
476
|
+
storage: getStorage(),
|
|
477
|
+
token: options.initialToken
|
|
478
|
+
});
|
|
479
|
+
let hasSetInitialToken = false;
|
|
480
|
+
const setInitialToken = async () => {
|
|
481
|
+
if (options.initialToken && !hasSetInitialToken) {
|
|
482
|
+
await client.setSession({ access_token: options.initialToken });
|
|
483
|
+
hasSetInitialToken = true;
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
const state = (0, vue.reactive)({
|
|
487
|
+
user: null,
|
|
488
|
+
isAuthenticated: false,
|
|
489
|
+
isLoading: !options.initialToken,
|
|
490
|
+
currentOrganization: null,
|
|
491
|
+
organizations: []
|
|
492
|
+
});
|
|
493
|
+
const context = {
|
|
494
|
+
client,
|
|
495
|
+
state,
|
|
496
|
+
options
|
|
497
|
+
};
|
|
498
|
+
return { install(app) {
|
|
499
|
+
injectStyles();
|
|
500
|
+
if (options.appearance?.variables) applyVariables(options.appearance.variables);
|
|
501
|
+
if (options.org && !options.service) console.warn("[AuthOS] You provided \"org\" but not \"service\". OAuth flows may not work correctly.");
|
|
502
|
+
if (!options.org && options.service) console.warn("[AuthOS] You provided \"service\" but not \"org\". OAuth flows may not work correctly.");
|
|
503
|
+
(0, vue.nextTick)(() => {
|
|
504
|
+
setInitialToken();
|
|
505
|
+
});
|
|
506
|
+
client.onAuthStateChange(async (isAuthenticated) => {
|
|
507
|
+
state.isAuthenticated = isAuthenticated;
|
|
508
|
+
state.isLoading = false;
|
|
509
|
+
if (isAuthenticated) {
|
|
510
|
+
try {
|
|
511
|
+
state.user = await client.user.getProfile();
|
|
512
|
+
} catch {
|
|
513
|
+
state.user = null;
|
|
514
|
+
}
|
|
515
|
+
try {
|
|
516
|
+
const orgs = await client.organizations.list();
|
|
517
|
+
state.organizations = orgs;
|
|
518
|
+
if (orgs.length > 0 && !state.currentOrganization) state.currentOrganization = orgs[0];
|
|
519
|
+
} catch {
|
|
520
|
+
state.organizations = [];
|
|
521
|
+
}
|
|
522
|
+
} else {
|
|
523
|
+
state.user = null;
|
|
524
|
+
state.currentOrganization = null;
|
|
525
|
+
state.organizations = [];
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
app.provide(require_useAuthOS.AUTH_OS_INJECTION_KEY, context);
|
|
529
|
+
app.config.globalProperties.$authOS = context;
|
|
530
|
+
} };
|
|
572
531
|
}
|
|
532
|
+
//#endregion
|
|
533
|
+
//#region src/composables/useUser.ts
|
|
573
534
|
function useUser() {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
return {
|
|
584
|
-
user,
|
|
585
|
-
isLoading
|
|
586
|
-
};
|
|
535
|
+
const context = (0, vue.inject)(require_useAuthOS.AUTH_OS_INJECTION_KEY);
|
|
536
|
+
if (!context) return {
|
|
537
|
+
user: (0, vue.ref)(null),
|
|
538
|
+
isLoading: (0, vue.computed)(() => false)
|
|
539
|
+
};
|
|
540
|
+
return {
|
|
541
|
+
user: (0, vue.computed)(() => context.state.user),
|
|
542
|
+
isLoading: (0, vue.computed)(() => context.state.isLoading)
|
|
543
|
+
};
|
|
587
544
|
}
|
|
545
|
+
//#endregion
|
|
546
|
+
//#region src/composables/useOrganization.ts
|
|
547
|
+
/**
|
|
548
|
+
* Composable to access the current organization context and switch between organizations.
|
|
549
|
+
*
|
|
550
|
+
* When switching organizations, this calls the backend to issue new JWT tokens
|
|
551
|
+
* with the organization context, enabling seamless organization switching without
|
|
552
|
+
* requiring re-authentication.
|
|
553
|
+
*
|
|
554
|
+
* @returns The current organization and a function to switch organizations
|
|
555
|
+
*
|
|
556
|
+
* @example
|
|
557
|
+
* ```vue
|
|
558
|
+
* <script setup>
|
|
559
|
+
* import { useOrganization } from '@drmhse/authos-vue';
|
|
560
|
+
*
|
|
561
|
+
* const { currentOrganization, switchOrganization, isSwitching } = useOrganization();
|
|
562
|
+
* <\/script>
|
|
563
|
+
* ```
|
|
564
|
+
*/
|
|
588
565
|
function useOrganization() {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
isSwitching
|
|
622
|
-
};
|
|
566
|
+
const context = (0, vue.inject)(require_useAuthOS.AUTH_OS_INJECTION_KEY);
|
|
567
|
+
if (!context) return {
|
|
568
|
+
currentOrganization: (0, vue.ref)(null),
|
|
569
|
+
organizations: (0, vue.ref)([]),
|
|
570
|
+
switchOrganization: async () => null,
|
|
571
|
+
isSwitching: (0, vue.ref)(false)
|
|
572
|
+
};
|
|
573
|
+
const currentOrganization = (0, vue.computed)(() => context.state.currentOrganization);
|
|
574
|
+
const organizations = (0, vue.computed)(() => context.state.organizations);
|
|
575
|
+
const isSwitching = (0, vue.ref)(false);
|
|
576
|
+
async function switchOrganization(slug) {
|
|
577
|
+
if (!context) return;
|
|
578
|
+
isSwitching.value = true;
|
|
579
|
+
try {
|
|
580
|
+
const result = await context.client.organizations.select(slug);
|
|
581
|
+
await context.client.setSession({
|
|
582
|
+
access_token: result.access_token,
|
|
583
|
+
refresh_token: result.refresh_token
|
|
584
|
+
});
|
|
585
|
+
const orgResponse = await context.client.organizations.get(slug);
|
|
586
|
+
context.state.currentOrganization = orgResponse;
|
|
587
|
+
return orgResponse;
|
|
588
|
+
} finally {
|
|
589
|
+
isSwitching.value = false;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return {
|
|
593
|
+
currentOrganization,
|
|
594
|
+
organizations,
|
|
595
|
+
switchOrganization,
|
|
596
|
+
isSwitching
|
|
597
|
+
};
|
|
623
598
|
}
|
|
599
|
+
//#endregion
|
|
600
|
+
//#region src/composables/usePermission.ts
|
|
601
|
+
/**
|
|
602
|
+
* Check if the current user has a specific permission.
|
|
603
|
+
*
|
|
604
|
+
* @param permission The permission to check
|
|
605
|
+
* @returns A computed ref that is true if the user has the permission
|
|
606
|
+
*
|
|
607
|
+
* @example
|
|
608
|
+
* ```vue
|
|
609
|
+
* <script setup>
|
|
610
|
+
* import { usePermission } from '@drmhse/authos-vue';
|
|
611
|
+
*
|
|
612
|
+
* const canAccessAdmin = usePermission('admin:access');
|
|
613
|
+
* <\/script>
|
|
614
|
+
*
|
|
615
|
+
* <template>
|
|
616
|
+
* <button v-if="canAccessAdmin">Admin Panel</button>
|
|
617
|
+
* </template>
|
|
618
|
+
* ```
|
|
619
|
+
*/
|
|
624
620
|
function usePermission(permission) {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
621
|
+
const { user } = useUser();
|
|
622
|
+
return (0, vue.computed)(() => {
|
|
623
|
+
if (!user.value || !permission) return false;
|
|
624
|
+
return user.value.permissions?.includes(permission) ?? false;
|
|
625
|
+
});
|
|
630
626
|
}
|
|
627
|
+
/**
|
|
628
|
+
* Check if the current user has any of the specified permissions.
|
|
629
|
+
*
|
|
630
|
+
* @param permissions The permissions to check
|
|
631
|
+
* @returns A computed ref that is true if the user has any of the permissions
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
* ```vue
|
|
635
|
+
* <script setup>
|
|
636
|
+
* import { useAnyPermission } from '@drmhse/authos-vue';
|
|
637
|
+
*
|
|
638
|
+
* const canAccessReports = useAnyPermission(['reports:read', 'admin:access']);
|
|
639
|
+
* <\/script>
|
|
640
|
+
* ```
|
|
641
|
+
*/
|
|
631
642
|
function useAnyPermission(permissions) {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
643
|
+
const { user } = useUser();
|
|
644
|
+
return (0, vue.computed)(() => {
|
|
645
|
+
if (!user.value || permissions.length === 0) return false;
|
|
646
|
+
return permissions.some((p) => user.value?.permissions?.includes(p));
|
|
647
|
+
});
|
|
637
648
|
}
|
|
649
|
+
/**
|
|
650
|
+
* Check if the current user has all of the specified permissions.
|
|
651
|
+
*
|
|
652
|
+
* @param permissions The permissions to check
|
|
653
|
+
* @returns A computed ref that is true if the user has all of the permissions
|
|
654
|
+
*
|
|
655
|
+
* @example
|
|
656
|
+
* ```vue
|
|
657
|
+
* <script setup>
|
|
658
|
+
* import { useAllPermissions } from '@drmhse/authos-vue';
|
|
659
|
+
*
|
|
660
|
+
* const canManageBilling = useAllPermissions(['billing:read', 'billing:write']);
|
|
661
|
+
* <\/script>
|
|
662
|
+
* ```
|
|
663
|
+
*/
|
|
638
664
|
function useAllPermissions(permissions) {
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
665
|
+
const { user } = useUser();
|
|
666
|
+
return (0, vue.computed)(() => {
|
|
667
|
+
if (!user.value || permissions.length === 0) return false;
|
|
668
|
+
return permissions.every((p) => user.value?.permissions?.includes(p));
|
|
669
|
+
});
|
|
644
670
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
671
|
+
//#endregion
|
|
672
|
+
//#region src/components/AuthOSProvider.ts
|
|
673
|
+
const AuthOSProvider = (0, vue.defineComponent)({
|
|
674
|
+
name: "AuthOSProvider",
|
|
675
|
+
props: {
|
|
676
|
+
baseURL: {
|
|
677
|
+
type: String,
|
|
678
|
+
required: true
|
|
679
|
+
},
|
|
680
|
+
org: {
|
|
681
|
+
type: String,
|
|
682
|
+
default: void 0
|
|
683
|
+
},
|
|
684
|
+
service: {
|
|
685
|
+
type: String,
|
|
686
|
+
default: void 0
|
|
687
|
+
},
|
|
688
|
+
redirectUri: {
|
|
689
|
+
type: String,
|
|
690
|
+
default: void 0
|
|
691
|
+
},
|
|
692
|
+
storage: {
|
|
693
|
+
type: Object,
|
|
694
|
+
default: void 0
|
|
695
|
+
},
|
|
696
|
+
client: {
|
|
697
|
+
type: Object,
|
|
698
|
+
default: void 0
|
|
699
|
+
}
|
|
700
|
+
},
|
|
701
|
+
setup(props, { slots }) {
|
|
702
|
+
const getStorage = () => {
|
|
703
|
+
if (props.storage) return props.storage;
|
|
704
|
+
if (typeof window !== "undefined") return new _drmhse_sso_sdk.BrowserStorage();
|
|
705
|
+
return new _drmhse_sso_sdk.MemoryStorage();
|
|
706
|
+
};
|
|
707
|
+
const client = props.client ?? new _drmhse_sso_sdk.SsoClient({
|
|
708
|
+
baseURL: props.baseURL,
|
|
709
|
+
storage: getStorage()
|
|
710
|
+
});
|
|
711
|
+
const state = (0, vue.reactive)({
|
|
712
|
+
user: null,
|
|
713
|
+
isAuthenticated: false,
|
|
714
|
+
isLoading: true,
|
|
715
|
+
currentOrganization: null,
|
|
716
|
+
organizations: []
|
|
717
|
+
});
|
|
718
|
+
(0, vue.provide)(require_useAuthOS.AUTH_OS_INJECTION_KEY, {
|
|
719
|
+
client,
|
|
720
|
+
state,
|
|
721
|
+
options: {
|
|
722
|
+
baseURL: props.baseURL,
|
|
723
|
+
org: props.org,
|
|
724
|
+
service: props.service,
|
|
725
|
+
redirectUri: props.redirectUri
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
let unsubscribe;
|
|
729
|
+
(0, vue.onMounted)(() => {
|
|
730
|
+
unsubscribe = client.onAuthStateChange(async (isAuthenticated) => {
|
|
731
|
+
state.isAuthenticated = isAuthenticated;
|
|
732
|
+
state.isLoading = false;
|
|
733
|
+
if (isAuthenticated) {
|
|
734
|
+
try {
|
|
735
|
+
state.user = await client.user.getProfile();
|
|
736
|
+
} catch {
|
|
737
|
+
state.user = null;
|
|
738
|
+
}
|
|
739
|
+
try {
|
|
740
|
+
const orgs = await client.organizations.list();
|
|
741
|
+
state.organizations = orgs;
|
|
742
|
+
if (orgs.length > 0 && !state.currentOrganization) state.currentOrganization = orgs[0];
|
|
743
|
+
} catch {
|
|
744
|
+
state.organizations = [];
|
|
745
|
+
}
|
|
746
|
+
} else {
|
|
747
|
+
state.user = null;
|
|
748
|
+
state.currentOrganization = null;
|
|
749
|
+
state.organizations = [];
|
|
750
|
+
}
|
|
751
|
+
});
|
|
752
|
+
});
|
|
753
|
+
(0, vue.onUnmounted)(() => {
|
|
754
|
+
unsubscribe?.();
|
|
755
|
+
});
|
|
756
|
+
return () => slots.default ? slots.default() : (0, vue.h)("div");
|
|
757
|
+
}
|
|
731
758
|
});
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
vue.h("button", {
|
|
876
|
-
type: "submit",
|
|
877
|
-
disabled: isSubmitting.value,
|
|
878
|
-
"data-authos-submit": ""
|
|
879
|
-
}, isSubmitting.value ? "Signing in..." : "Sign In")
|
|
880
|
-
])
|
|
881
|
-
]);
|
|
882
|
-
};
|
|
883
|
-
}
|
|
759
|
+
//#endregion
|
|
760
|
+
//#region src/components/SignIn.ts
|
|
761
|
+
const MFA_PREAUTH_EXPIRY = 300;
|
|
762
|
+
const SignIn = (0, vue.defineComponent)({
|
|
763
|
+
name: "SignIn",
|
|
764
|
+
props: {
|
|
765
|
+
onSuccess: {
|
|
766
|
+
type: Function,
|
|
767
|
+
default: void 0
|
|
768
|
+
},
|
|
769
|
+
onError: {
|
|
770
|
+
type: Function,
|
|
771
|
+
default: void 0
|
|
772
|
+
}
|
|
773
|
+
},
|
|
774
|
+
emits: ["success", "error"],
|
|
775
|
+
setup(props, { slots, emit }) {
|
|
776
|
+
const { client, options } = require_useAuthOS.useAuthOS();
|
|
777
|
+
const email = (0, vue.ref)("");
|
|
778
|
+
const password = (0, vue.ref)("");
|
|
779
|
+
const mfaCode = (0, vue.ref)("");
|
|
780
|
+
const preauthToken = (0, vue.ref)("");
|
|
781
|
+
const step = (0, vue.ref)("credentials");
|
|
782
|
+
const error = (0, vue.ref)(null);
|
|
783
|
+
const isSubmitting = (0, vue.ref)(false);
|
|
784
|
+
async function submit() {
|
|
785
|
+
error.value = null;
|
|
786
|
+
isSubmitting.value = true;
|
|
787
|
+
try {
|
|
788
|
+
if (step.value === "credentials") {
|
|
789
|
+
const result = await client.auth.login({
|
|
790
|
+
email: email.value,
|
|
791
|
+
password: password.value,
|
|
792
|
+
org_slug: options.org,
|
|
793
|
+
service_slug: options.service
|
|
794
|
+
});
|
|
795
|
+
if (result.expires_in === MFA_PREAUTH_EXPIRY) {
|
|
796
|
+
preauthToken.value = result.access_token;
|
|
797
|
+
step.value = "mfa";
|
|
798
|
+
} else {
|
|
799
|
+
emit("success");
|
|
800
|
+
props.onSuccess?.();
|
|
801
|
+
}
|
|
802
|
+
} else {
|
|
803
|
+
await client.auth.verifyMfa(preauthToken.value, mfaCode.value);
|
|
804
|
+
emit("success");
|
|
805
|
+
props.onSuccess?.();
|
|
806
|
+
}
|
|
807
|
+
} catch (err) {
|
|
808
|
+
const message = err instanceof _drmhse_sso_sdk.SsoApiError ? err.message : "Login failed";
|
|
809
|
+
error.value = message;
|
|
810
|
+
const e = err instanceof Error ? err : new Error(message);
|
|
811
|
+
emit("error", e);
|
|
812
|
+
props.onError?.(e);
|
|
813
|
+
} finally {
|
|
814
|
+
isSubmitting.value = false;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
return () => {
|
|
818
|
+
const slotProps = {
|
|
819
|
+
email: email.value,
|
|
820
|
+
password: password.value,
|
|
821
|
+
mfaCode: mfaCode.value,
|
|
822
|
+
step: step.value,
|
|
823
|
+
error: error.value,
|
|
824
|
+
isSubmitting: isSubmitting.value,
|
|
825
|
+
updateEmail: (v) => email.value = v,
|
|
826
|
+
updatePassword: (v) => password.value = v,
|
|
827
|
+
updateMfaCode: (v) => mfaCode.value = v,
|
|
828
|
+
submit
|
|
829
|
+
};
|
|
830
|
+
if (slots.default) return slots.default(slotProps);
|
|
831
|
+
if (step.value === "mfa") return (0, vue.h)("div", {
|
|
832
|
+
"data-authos-signin": "",
|
|
833
|
+
"data-state": "mfa"
|
|
834
|
+
}, [(0, vue.h)("form", { onSubmit: (e) => {
|
|
835
|
+
e.preventDefault();
|
|
836
|
+
submit();
|
|
837
|
+
} }, [
|
|
838
|
+
(0, vue.h)("div", { "data-authos-field": "mfa-code" }, [(0, vue.h)("label", { for: "authos-mfa-code" }, "Verification Code"), (0, vue.h)("input", {
|
|
839
|
+
id: "authos-mfa-code",
|
|
840
|
+
type: "text",
|
|
841
|
+
inputMode: "numeric",
|
|
842
|
+
autocomplete: "one-time-code",
|
|
843
|
+
value: mfaCode.value,
|
|
844
|
+
placeholder: "Enter 6-digit code",
|
|
845
|
+
required: true,
|
|
846
|
+
disabled: isSubmitting.value,
|
|
847
|
+
onInput: (e) => mfaCode.value = e.target.value
|
|
848
|
+
})]),
|
|
849
|
+
error.value && (0, vue.h)("div", { "data-authos-error": "" }, error.value),
|
|
850
|
+
(0, vue.h)("button", {
|
|
851
|
+
type: "submit",
|
|
852
|
+
disabled: isSubmitting.value,
|
|
853
|
+
"data-authos-submit": ""
|
|
854
|
+
}, isSubmitting.value ? "Verifying..." : "Verify"),
|
|
855
|
+
(0, vue.h)("button", {
|
|
856
|
+
type: "button",
|
|
857
|
+
"data-authos-back": "",
|
|
858
|
+
onClick: () => {
|
|
859
|
+
step.value = "credentials";
|
|
860
|
+
mfaCode.value = "";
|
|
861
|
+
preauthToken.value = "";
|
|
862
|
+
error.value = null;
|
|
863
|
+
}
|
|
864
|
+
}, "Back to login")
|
|
865
|
+
])]);
|
|
866
|
+
return (0, vue.h)("div", {
|
|
867
|
+
"data-authos-signin": "",
|
|
868
|
+
"data-state": "credentials"
|
|
869
|
+
}, [(0, vue.h)("form", { onSubmit: (e) => {
|
|
870
|
+
e.preventDefault();
|
|
871
|
+
submit();
|
|
872
|
+
} }, [
|
|
873
|
+
(0, vue.h)("div", { "data-authos-field": "email" }, [(0, vue.h)("label", { for: "authos-email" }, "Email"), (0, vue.h)("input", {
|
|
874
|
+
id: "authos-email",
|
|
875
|
+
type: "email",
|
|
876
|
+
autocomplete: "email",
|
|
877
|
+
value: email.value,
|
|
878
|
+
placeholder: "Enter your email",
|
|
879
|
+
required: true,
|
|
880
|
+
disabled: isSubmitting.value,
|
|
881
|
+
onInput: (e) => email.value = e.target.value
|
|
882
|
+
})]),
|
|
883
|
+
(0, vue.h)("div", { "data-authos-field": "password" }, [(0, vue.h)("label", { for: "authos-password" }, "Password"), (0, vue.h)("input", {
|
|
884
|
+
id: "authos-password",
|
|
885
|
+
type: "password",
|
|
886
|
+
autocomplete: "current-password",
|
|
887
|
+
value: password.value,
|
|
888
|
+
placeholder: "Enter your password",
|
|
889
|
+
required: true,
|
|
890
|
+
disabled: isSubmitting.value,
|
|
891
|
+
onInput: (e) => password.value = e.target.value
|
|
892
|
+
})]),
|
|
893
|
+
error.value && (0, vue.h)("div", { "data-authos-error": "" }, error.value),
|
|
894
|
+
(0, vue.h)("button", {
|
|
895
|
+
type: "submit",
|
|
896
|
+
disabled: isSubmitting.value,
|
|
897
|
+
"data-authos-submit": ""
|
|
898
|
+
}, isSubmitting.value ? "Signing in..." : "Sign In")
|
|
899
|
+
])]);
|
|
900
|
+
};
|
|
901
|
+
}
|
|
884
902
|
});
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
903
|
+
//#endregion
|
|
904
|
+
//#region src/components/OAuthButton.ts
|
|
905
|
+
/**
|
|
906
|
+
* Human-readable provider names for button labels
|
|
907
|
+
*/
|
|
908
|
+
const PROVIDER_NAMES = {
|
|
909
|
+
github: "GitHub",
|
|
910
|
+
google: "Google",
|
|
911
|
+
microsoft: "Microsoft"
|
|
889
912
|
};
|
|
913
|
+
/**
|
|
914
|
+
* SVG icons for each OAuth provider
|
|
915
|
+
*/
|
|
890
916
|
function getProviderIcon(provider) {
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
917
|
+
switch (provider) {
|
|
918
|
+
case "github": return (0, vue.h)("svg", {
|
|
919
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
920
|
+
viewBox: "0 0 24 24",
|
|
921
|
+
fill: "currentColor",
|
|
922
|
+
"aria-hidden": "true"
|
|
923
|
+
}, [(0, vue.h)("path", { d: "M12 0C5.374 0 0 5.373 0 12c0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576C20.566 21.797 24 17.3 24 12c0-6.627-5.373-12-12-12z" })]);
|
|
924
|
+
case "google": return (0, vue.h)("svg", {
|
|
925
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
926
|
+
viewBox: "0 0 24 24",
|
|
927
|
+
"aria-hidden": "true"
|
|
928
|
+
}, [
|
|
929
|
+
(0, vue.h)("path", {
|
|
930
|
+
fill: "#4285F4",
|
|
931
|
+
d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
|
|
932
|
+
}),
|
|
933
|
+
(0, vue.h)("path", {
|
|
934
|
+
fill: "#34A853",
|
|
935
|
+
d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
|
|
936
|
+
}),
|
|
937
|
+
(0, vue.h)("path", {
|
|
938
|
+
fill: "#FBBC05",
|
|
939
|
+
d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
|
|
940
|
+
}),
|
|
941
|
+
(0, vue.h)("path", {
|
|
942
|
+
fill: "#EA4335",
|
|
943
|
+
d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
|
944
|
+
})
|
|
945
|
+
]);
|
|
946
|
+
case "microsoft": return (0, vue.h)("svg", {
|
|
947
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
948
|
+
viewBox: "0 0 23 23",
|
|
949
|
+
"aria-hidden": "true"
|
|
950
|
+
}, [
|
|
951
|
+
(0, vue.h)("path", {
|
|
952
|
+
fill: "#f35325",
|
|
953
|
+
d: "M1 1h10v10H1z"
|
|
954
|
+
}),
|
|
955
|
+
(0, vue.h)("path", {
|
|
956
|
+
fill: "#81bc06",
|
|
957
|
+
d: "M12 1h10v10H12z"
|
|
958
|
+
}),
|
|
959
|
+
(0, vue.h)("path", {
|
|
960
|
+
fill: "#05a6f0",
|
|
961
|
+
d: "M1 12h10v10H1z"
|
|
962
|
+
}),
|
|
963
|
+
(0, vue.h)("path", {
|
|
964
|
+
fill: "#ffba08",
|
|
965
|
+
d: "M12 12h10v10H12z"
|
|
966
|
+
})
|
|
967
|
+
]);
|
|
968
|
+
}
|
|
938
969
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
);
|
|
1007
|
-
};
|
|
1008
|
-
}
|
|
970
|
+
/**
|
|
971
|
+
* OAuth login button for a specific provider.
|
|
972
|
+
* Redirects the user to the OAuth provider's login page.
|
|
973
|
+
*
|
|
974
|
+
* Requires `org` and `service` to be configured in createAuthOS options.
|
|
975
|
+
*
|
|
976
|
+
* @example
|
|
977
|
+
* ```vue
|
|
978
|
+
* <script setup>
|
|
979
|
+
* import { OAuthButton } from '@drmhse/authos-vue';
|
|
980
|
+
* <\/script>
|
|
981
|
+
*
|
|
982
|
+
* <template>
|
|
983
|
+
* <OAuthButton provider="github" />
|
|
984
|
+
* <OAuthButton provider="google">Sign in with Google</OAuthButton>
|
|
985
|
+
* </template>
|
|
986
|
+
* ```
|
|
987
|
+
*/
|
|
988
|
+
const OAuthButton = (0, vue.defineComponent)({
|
|
989
|
+
name: "OAuthButton",
|
|
990
|
+
props: {
|
|
991
|
+
provider: {
|
|
992
|
+
type: String,
|
|
993
|
+
required: true
|
|
994
|
+
},
|
|
995
|
+
disabled: {
|
|
996
|
+
type: Boolean,
|
|
997
|
+
default: false
|
|
998
|
+
}
|
|
999
|
+
},
|
|
1000
|
+
emits: ["redirect"],
|
|
1001
|
+
setup(props, { slots, emit }) {
|
|
1002
|
+
const { client, options } = require_useAuthOS.useAuthOS();
|
|
1003
|
+
const isConfigured = (0, vue.computed)(() => !!(options.org && options.service));
|
|
1004
|
+
const providerName = (0, vue.computed)(() => PROVIDER_NAMES[props.provider]);
|
|
1005
|
+
function handleClick() {
|
|
1006
|
+
if (!options.org || !options.service) {
|
|
1007
|
+
console.error(`[AuthOS] OAuth login requires "org" and "service" in createAuthOS options.\nCurrent options: { org: ${options.org ? `"${options.org}"` : "undefined"}, service: ${options.service ? `"${options.service}"` : "undefined"} }\n\nExample:\n app.use(createAuthOS({\n baseURL: "${options.baseURL}",\n org: "your-org-slug",\n service: "your-service-slug",\n }));\n\nSee: https://docs.authos.dev/vue/oauth-setup`);
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
const redirectUri = options.redirectUri ?? (typeof window !== "undefined" ? window.location.origin + "/callback" : void 0);
|
|
1011
|
+
const url = client.auth.getLoginUrl(props.provider, {
|
|
1012
|
+
org: options.org,
|
|
1013
|
+
service: options.service,
|
|
1014
|
+
redirect_uri: redirectUri
|
|
1015
|
+
});
|
|
1016
|
+
emit("redirect");
|
|
1017
|
+
window.location.href = url;
|
|
1018
|
+
}
|
|
1019
|
+
return () => {
|
|
1020
|
+
const slotProps = {
|
|
1021
|
+
provider: props.provider,
|
|
1022
|
+
providerName: providerName.value,
|
|
1023
|
+
isConfigured: isConfigured.value,
|
|
1024
|
+
disabled: props.disabled,
|
|
1025
|
+
handleClick
|
|
1026
|
+
};
|
|
1027
|
+
if (slots.default) return slots.default(slotProps);
|
|
1028
|
+
return (0, vue.h)("button", {
|
|
1029
|
+
type: "button",
|
|
1030
|
+
onClick: handleClick,
|
|
1031
|
+
disabled: props.disabled || !isConfigured.value,
|
|
1032
|
+
"data-authos-oauth": "",
|
|
1033
|
+
"data-provider": props.provider
|
|
1034
|
+
}, [getProviderIcon(props.provider), (0, vue.h)("span", `Continue with ${providerName.value}`)]);
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1009
1037
|
});
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
required: true,
|
|
1171
|
-
disabled: isSubmitting.value,
|
|
1172
|
-
onInput: (e) => confirmPassword.value = e.target.value
|
|
1173
|
-
})
|
|
1174
|
-
]),
|
|
1175
|
-
error.value && vue.h("div", { "data-authos-error": "" }, error.value),
|
|
1176
|
-
vue.h("button", {
|
|
1177
|
-
type: "submit",
|
|
1178
|
-
disabled: isSubmitting.value,
|
|
1179
|
-
"data-authos-submit": ""
|
|
1180
|
-
}, isSubmitting.value ? "Creating account..." : "Sign Up"),
|
|
1181
|
-
// Sign In Link
|
|
1182
|
-
props.showSignIn && vue.h("div", { "data-authos-signin-prompt": "" }, [
|
|
1183
|
-
"Already have an account? ",
|
|
1184
|
-
vue.h("a", { href: "/signin", "data-authos-link": "signin" }, "Sign in")
|
|
1185
|
-
])
|
|
1186
|
-
])
|
|
1187
|
-
]);
|
|
1188
|
-
};
|
|
1189
|
-
}
|
|
1038
|
+
//#endregion
|
|
1039
|
+
//#region src/components/SignUp.ts
|
|
1040
|
+
const SignUp = (0, vue.defineComponent)({
|
|
1041
|
+
name: "SignUp",
|
|
1042
|
+
props: {
|
|
1043
|
+
onSuccess: {
|
|
1044
|
+
type: Function,
|
|
1045
|
+
default: void 0
|
|
1046
|
+
},
|
|
1047
|
+
onError: {
|
|
1048
|
+
type: Function,
|
|
1049
|
+
default: void 0
|
|
1050
|
+
},
|
|
1051
|
+
/** Organization slug for tenant context */
|
|
1052
|
+
orgSlug: {
|
|
1053
|
+
type: String,
|
|
1054
|
+
default: void 0
|
|
1055
|
+
},
|
|
1056
|
+
/** Service slug for tenant attribution (used with orgSlug) */
|
|
1057
|
+
serviceSlug: {
|
|
1058
|
+
type: String,
|
|
1059
|
+
default: void 0
|
|
1060
|
+
},
|
|
1061
|
+
/** List of OAuth providers to display buttons for */
|
|
1062
|
+
providers: {
|
|
1063
|
+
type: [Array, Boolean],
|
|
1064
|
+
default: false
|
|
1065
|
+
},
|
|
1066
|
+
/** Show divider between OAuth and email form */
|
|
1067
|
+
showDivider: {
|
|
1068
|
+
type: Boolean,
|
|
1069
|
+
default: true
|
|
1070
|
+
},
|
|
1071
|
+
/** Show sign in link */
|
|
1072
|
+
showSignIn: {
|
|
1073
|
+
type: Boolean,
|
|
1074
|
+
default: true
|
|
1075
|
+
}
|
|
1076
|
+
},
|
|
1077
|
+
emits: ["success", "error"],
|
|
1078
|
+
setup(props, { slots, emit }) {
|
|
1079
|
+
const { client, options } = require_useAuthOS.useAuthOS();
|
|
1080
|
+
const email = (0, vue.ref)("");
|
|
1081
|
+
const password = (0, vue.ref)("");
|
|
1082
|
+
const confirmPassword = (0, vue.ref)("");
|
|
1083
|
+
const error = (0, vue.ref)(null);
|
|
1084
|
+
const isSubmitting = (0, vue.ref)(false);
|
|
1085
|
+
const isSuccess = (0, vue.ref)(false);
|
|
1086
|
+
const hasOAuthConfig = !!(options.org && options.service);
|
|
1087
|
+
const oauthProviders = Array.isArray(props.providers) ? props.providers : [];
|
|
1088
|
+
async function submit() {
|
|
1089
|
+
error.value = null;
|
|
1090
|
+
if (password.value !== confirmPassword.value) {
|
|
1091
|
+
error.value = "Passwords do not match";
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
if (password.value.length < 8) {
|
|
1095
|
+
error.value = "Password must be at least 8 characters";
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
isSubmitting.value = true;
|
|
1099
|
+
try {
|
|
1100
|
+
await client.auth.register({
|
|
1101
|
+
email: email.value,
|
|
1102
|
+
password: password.value,
|
|
1103
|
+
org_slug: props.orgSlug ?? options.org,
|
|
1104
|
+
service_slug: props.serviceSlug ?? options.service
|
|
1105
|
+
});
|
|
1106
|
+
isSuccess.value = true;
|
|
1107
|
+
emit("success");
|
|
1108
|
+
props.onSuccess?.();
|
|
1109
|
+
} catch (err) {
|
|
1110
|
+
const message = err instanceof _drmhse_sso_sdk.SsoApiError ? err.message : "Registration failed";
|
|
1111
|
+
error.value = message;
|
|
1112
|
+
const e = err instanceof Error ? err : new Error(message);
|
|
1113
|
+
emit("error", e);
|
|
1114
|
+
props.onError?.(e);
|
|
1115
|
+
} finally {
|
|
1116
|
+
isSubmitting.value = false;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
return () => {
|
|
1120
|
+
const slotProps = {
|
|
1121
|
+
email: email.value,
|
|
1122
|
+
password: password.value,
|
|
1123
|
+
error: error.value,
|
|
1124
|
+
isSubmitting: isSubmitting.value,
|
|
1125
|
+
updateEmail: (v) => email.value = v,
|
|
1126
|
+
updatePassword: (v) => password.value = v,
|
|
1127
|
+
submit
|
|
1128
|
+
};
|
|
1129
|
+
if (slots.default) return slots.default(slotProps);
|
|
1130
|
+
if (isSuccess.value) return (0, vue.h)("div", {
|
|
1131
|
+
"data-authos-signup": "",
|
|
1132
|
+
"data-state": "success"
|
|
1133
|
+
}, [(0, vue.h)("div", { "data-authos-success": "" }, [(0, vue.h)("h2", "Check your email"), (0, vue.h)("p", `We've sent a verification link to ${email.value}. Please click the link to verify your account.`)])]);
|
|
1134
|
+
return (0, vue.h)("div", {
|
|
1135
|
+
"data-authos-signup": "",
|
|
1136
|
+
"data-state": "credentials"
|
|
1137
|
+
}, [
|
|
1138
|
+
oauthProviders.length > 0 && (0, vue.h)("div", { "data-authos-oauth-section": "" }, [oauthProviders.map((provider) => (0, vue.h)(OAuthButton, {
|
|
1139
|
+
key: provider,
|
|
1140
|
+
provider,
|
|
1141
|
+
disabled: isSubmitting.value || !hasOAuthConfig
|
|
1142
|
+
})), !hasOAuthConfig && (0, vue.h)("p", {
|
|
1143
|
+
"data-authos-oauth-warning": "",
|
|
1144
|
+
style: {
|
|
1145
|
+
color: "orange",
|
|
1146
|
+
fontSize: "0.875rem"
|
|
1147
|
+
}
|
|
1148
|
+
}, "OAuth requires org and service in plugin options")]),
|
|
1149
|
+
oauthProviders.length > 0 && props.showDivider && (0, vue.h)("div", { "data-authos-divider": "" }, [(0, vue.h)("span", "or")]),
|
|
1150
|
+
(0, vue.h)("form", { onSubmit: (e) => {
|
|
1151
|
+
e.preventDefault();
|
|
1152
|
+
submit();
|
|
1153
|
+
} }, [
|
|
1154
|
+
(0, vue.h)("div", { "data-authos-field": "email" }, [(0, vue.h)("label", { for: "authos-signup-email" }, "Email"), (0, vue.h)("input", {
|
|
1155
|
+
id: "authos-signup-email",
|
|
1156
|
+
type: "email",
|
|
1157
|
+
autocomplete: "email",
|
|
1158
|
+
value: email.value,
|
|
1159
|
+
placeholder: "Enter your email",
|
|
1160
|
+
required: true,
|
|
1161
|
+
disabled: isSubmitting.value,
|
|
1162
|
+
onInput: (e) => email.value = e.target.value
|
|
1163
|
+
})]),
|
|
1164
|
+
(0, vue.h)("div", { "data-authos-field": "password" }, [(0, vue.h)("label", { for: "authos-signup-password" }, "Password"), (0, vue.h)("input", {
|
|
1165
|
+
id: "authos-signup-password",
|
|
1166
|
+
type: "password",
|
|
1167
|
+
autocomplete: "new-password",
|
|
1168
|
+
value: password.value,
|
|
1169
|
+
placeholder: "Create a password",
|
|
1170
|
+
required: true,
|
|
1171
|
+
disabled: isSubmitting.value,
|
|
1172
|
+
onInput: (e) => password.value = e.target.value
|
|
1173
|
+
})]),
|
|
1174
|
+
(0, vue.h)("div", { "data-authos-field": "confirm-password" }, [(0, vue.h)("label", { for: "authos-signup-confirm" }, "Confirm Password"), (0, vue.h)("input", {
|
|
1175
|
+
id: "authos-signup-confirm",
|
|
1176
|
+
type: "password",
|
|
1177
|
+
autocomplete: "new-password",
|
|
1178
|
+
value: confirmPassword.value,
|
|
1179
|
+
placeholder: "Confirm your password",
|
|
1180
|
+
required: true,
|
|
1181
|
+
disabled: isSubmitting.value,
|
|
1182
|
+
onInput: (e) => confirmPassword.value = e.target.value
|
|
1183
|
+
})]),
|
|
1184
|
+
error.value && (0, vue.h)("div", { "data-authos-error": "" }, error.value),
|
|
1185
|
+
(0, vue.h)("button", {
|
|
1186
|
+
type: "submit",
|
|
1187
|
+
disabled: isSubmitting.value,
|
|
1188
|
+
"data-authos-submit": ""
|
|
1189
|
+
}, isSubmitting.value ? "Creating account..." : "Sign Up"),
|
|
1190
|
+
props.showSignIn && (0, vue.h)("div", { "data-authos-signin-prompt": "" }, ["Already have an account? ", (0, vue.h)("a", {
|
|
1191
|
+
href: "/signin",
|
|
1192
|
+
"data-authos-link": "signin"
|
|
1193
|
+
}, "Sign in")])
|
|
1194
|
+
])
|
|
1195
|
+
]);
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1190
1198
|
});
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
(org) => vue.h("option", { key: org.organization.id, value: org.organization.slug }, org.organization.name)
|
|
1232
|
-
)
|
|
1233
|
-
) : "No organizations"
|
|
1234
|
-
);
|
|
1235
|
-
};
|
|
1236
|
-
}
|
|
1199
|
+
//#endregion
|
|
1200
|
+
//#region src/components/OrganizationSwitcher.ts
|
|
1201
|
+
const OrganizationSwitcher = (0, vue.defineComponent)({
|
|
1202
|
+
name: "OrganizationSwitcher",
|
|
1203
|
+
props: { onSwitch: {
|
|
1204
|
+
type: Function,
|
|
1205
|
+
default: void 0
|
|
1206
|
+
} },
|
|
1207
|
+
emits: ["switch"],
|
|
1208
|
+
setup(props, { slots, emit }) {
|
|
1209
|
+
const { currentOrganization, organizations, switchOrganization, isSwitching } = useOrganization();
|
|
1210
|
+
async function switchTo(slug) {
|
|
1211
|
+
await switchOrganization(slug);
|
|
1212
|
+
const org = organizations.value.find((o) => o.organization.slug === slug);
|
|
1213
|
+
if (org) {
|
|
1214
|
+
emit("switch", org);
|
|
1215
|
+
props.onSwitch?.(org);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
return () => {
|
|
1219
|
+
const slotProps = {
|
|
1220
|
+
currentOrganization: currentOrganization.value,
|
|
1221
|
+
organizations: organizations.value,
|
|
1222
|
+
isSwitching: isSwitching.value,
|
|
1223
|
+
switchTo
|
|
1224
|
+
};
|
|
1225
|
+
if (slots.default) return slots.default(slotProps);
|
|
1226
|
+
return (0, vue.h)("div", {
|
|
1227
|
+
"data-authos-orgswitcher": "",
|
|
1228
|
+
"data-state": organizations.value.length > 0 ? "ready" : "empty"
|
|
1229
|
+
}, organizations.value.length > 0 ? (0, vue.h)("select", {
|
|
1230
|
+
value: currentOrganization.value?.organization.slug ?? "",
|
|
1231
|
+
disabled: isSwitching.value,
|
|
1232
|
+
onChange: (e) => switchTo(e.target.value)
|
|
1233
|
+
}, organizations.value.map((org) => (0, vue.h)("option", {
|
|
1234
|
+
key: org.organization.id,
|
|
1235
|
+
value: org.organization.slug
|
|
1236
|
+
}, org.organization.name))) : "No organizations");
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1237
1239
|
});
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
};
|
|
1295
|
-
}
|
|
1240
|
+
//#endregion
|
|
1241
|
+
//#region src/components/UserButton.ts
|
|
1242
|
+
const UserButton = (0, vue.defineComponent)({
|
|
1243
|
+
name: "UserButton",
|
|
1244
|
+
props: { onLogout: {
|
|
1245
|
+
type: Function,
|
|
1246
|
+
default: void 0
|
|
1247
|
+
} },
|
|
1248
|
+
emits: ["logout"],
|
|
1249
|
+
setup(props, { slots, emit }) {
|
|
1250
|
+
const { user, isLoading } = useUser();
|
|
1251
|
+
const { client } = require_useAuthOS.useAuthOS();
|
|
1252
|
+
const isLoggingOut = (0, vue.ref)(false);
|
|
1253
|
+
async function logout() {
|
|
1254
|
+
isLoggingOut.value = true;
|
|
1255
|
+
try {
|
|
1256
|
+
await client.auth.logout();
|
|
1257
|
+
emit("logout");
|
|
1258
|
+
props.onLogout?.();
|
|
1259
|
+
} finally {
|
|
1260
|
+
isLoggingOut.value = false;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
return () => {
|
|
1264
|
+
const slotProps = {
|
|
1265
|
+
user: user.value,
|
|
1266
|
+
isLoading: isLoading.value,
|
|
1267
|
+
isLoggingOut: isLoggingOut.value,
|
|
1268
|
+
logout
|
|
1269
|
+
};
|
|
1270
|
+
if (slots.default) return slots.default(slotProps);
|
|
1271
|
+
if (isLoading.value) return (0, vue.h)("div", {
|
|
1272
|
+
"data-authos-userbutton": "",
|
|
1273
|
+
"data-state": "loading"
|
|
1274
|
+
}, "Loading...");
|
|
1275
|
+
if (!user.value) return (0, vue.h)("div", {
|
|
1276
|
+
"data-authos-userbutton": "",
|
|
1277
|
+
"data-state": "signed-out"
|
|
1278
|
+
}, "Not signed in");
|
|
1279
|
+
const getInitials = (email) => {
|
|
1280
|
+
return email.split("@")[0].substring(0, 2).toUpperCase();
|
|
1281
|
+
};
|
|
1282
|
+
return (0, vue.h)("div", {
|
|
1283
|
+
"data-authos-userbutton": "",
|
|
1284
|
+
"data-state": "signed-in"
|
|
1285
|
+
}, [
|
|
1286
|
+
(0, vue.h)("div", { "data-authos-avatar": "" }, getInitials(user.value.email)),
|
|
1287
|
+
(0, vue.h)("span", { "data-authos-email": "" }, user.value.email),
|
|
1288
|
+
(0, vue.h)("button", {
|
|
1289
|
+
"data-authos-logout": "",
|
|
1290
|
+
onClick: logout,
|
|
1291
|
+
disabled: isLoggingOut.value
|
|
1292
|
+
}, isLoggingOut.value ? "Logging out..." : "Logout")
|
|
1293
|
+
]);
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
1296
|
});
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1297
|
+
//#endregion
|
|
1298
|
+
//#region src/components/Protect.ts
|
|
1299
|
+
const Protect = (0, vue.defineComponent)({
|
|
1300
|
+
name: "Protect",
|
|
1301
|
+
props: {
|
|
1302
|
+
permission: {
|
|
1303
|
+
type: String,
|
|
1304
|
+
default: void 0
|
|
1305
|
+
},
|
|
1306
|
+
permissions: {
|
|
1307
|
+
type: Array,
|
|
1308
|
+
default: void 0
|
|
1309
|
+
},
|
|
1310
|
+
requireAll: {
|
|
1311
|
+
type: Boolean,
|
|
1312
|
+
default: false
|
|
1313
|
+
},
|
|
1314
|
+
fallback: {
|
|
1315
|
+
type: [Object, Function],
|
|
1316
|
+
default: void 0
|
|
1317
|
+
}
|
|
1318
|
+
},
|
|
1319
|
+
setup(props, { slots }) {
|
|
1320
|
+
const { user, isLoading } = useUser();
|
|
1321
|
+
const hasAccess = (0, vue.computed)(() => {
|
|
1322
|
+
if (isLoading.value || !user.value) return false;
|
|
1323
|
+
const userPermissions = user.value.permissions ?? [];
|
|
1324
|
+
if (props.permission) return userPermissions.includes(props.permission);
|
|
1325
|
+
if (props.permissions && props.permissions.length > 0) {
|
|
1326
|
+
if (props.requireAll) return props.permissions.every((p) => userPermissions.includes(p));
|
|
1327
|
+
return props.permissions.some((p) => userPermissions.includes(p));
|
|
1328
|
+
}
|
|
1329
|
+
return true;
|
|
1330
|
+
});
|
|
1331
|
+
return () => {
|
|
1332
|
+
if (isLoading.value) return (0, vue.h)("div", {
|
|
1333
|
+
"data-authos-protect": "",
|
|
1334
|
+
"data-state": "loading"
|
|
1335
|
+
});
|
|
1336
|
+
if (hasAccess.value) return (0, vue.h)("div", {
|
|
1337
|
+
"data-authos-protect": "",
|
|
1338
|
+
"data-state": "allowed"
|
|
1339
|
+
}, slots.default?.());
|
|
1340
|
+
if (props.fallback) return (0, vue.h)("div", {
|
|
1341
|
+
"data-authos-protect": "",
|
|
1342
|
+
"data-state": "denied"
|
|
1343
|
+
}, [typeof props.fallback === "function" ? props.fallback() : props.fallback]);
|
|
1344
|
+
if (slots.fallback) return (0, vue.h)("div", {
|
|
1345
|
+
"data-authos-protect": "",
|
|
1346
|
+
"data-state": "denied"
|
|
1347
|
+
}, slots.fallback());
|
|
1348
|
+
return (0, vue.h)("div", {
|
|
1349
|
+
"data-authos-protect": "",
|
|
1350
|
+
"data-state": "denied"
|
|
1351
|
+
});
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1352
1354
|
});
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1355
|
+
//#endregion
|
|
1356
|
+
//#region src/components/SignedIn.ts
|
|
1357
|
+
/**
|
|
1358
|
+
* Renders children only when the user is authenticated.
|
|
1359
|
+
* Use with SignedOut to create conditional UI based on auth state.
|
|
1360
|
+
*
|
|
1361
|
+
* @example
|
|
1362
|
+
* ```vue
|
|
1363
|
+
* <script setup>
|
|
1364
|
+
* import { SignedIn, SignedOut, UserButton, SignIn } from '@drmhse/authos-vue';
|
|
1365
|
+
* <\/script>
|
|
1366
|
+
*
|
|
1367
|
+
* <template>
|
|
1368
|
+
* <header>
|
|
1369
|
+
* <SignedIn>
|
|
1370
|
+
* <UserButton />
|
|
1371
|
+
* </SignedIn>
|
|
1372
|
+
* <SignedOut>
|
|
1373
|
+
* <SignIn />
|
|
1374
|
+
* </SignedOut>
|
|
1375
|
+
* </header>
|
|
1376
|
+
* </template>
|
|
1377
|
+
* ```
|
|
1378
|
+
*/
|
|
1379
|
+
const SignedIn = (0, vue.defineComponent)({
|
|
1380
|
+
name: "SignedIn",
|
|
1381
|
+
setup(_, { slots }) {
|
|
1382
|
+
const { isAuthenticated, isLoading } = require_useAuthOS.useAuthOS();
|
|
1383
|
+
return () => {
|
|
1384
|
+
if (isLoading.value) return null;
|
|
1385
|
+
if (!isAuthenticated.value) return null;
|
|
1386
|
+
return slots.default?.();
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1367
1389
|
});
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1390
|
+
//#endregion
|
|
1391
|
+
//#region src/components/SignedOut.ts
|
|
1392
|
+
/**
|
|
1393
|
+
* Renders children only when the user is NOT authenticated.
|
|
1394
|
+
* Use with SignedIn to create conditional UI based on auth state.
|
|
1395
|
+
*
|
|
1396
|
+
* @example
|
|
1397
|
+
* ```vue
|
|
1398
|
+
* <script setup>
|
|
1399
|
+
* import { SignedIn, SignedOut, UserButton, SignIn } from '@drmhse/authos-vue';
|
|
1400
|
+
* <\/script>
|
|
1401
|
+
*
|
|
1402
|
+
* <template>
|
|
1403
|
+
* <header>
|
|
1404
|
+
* <SignedIn>
|
|
1405
|
+
* <UserButton />
|
|
1406
|
+
* </SignedIn>
|
|
1407
|
+
* <SignedOut>
|
|
1408
|
+
* <SignIn />
|
|
1409
|
+
* </SignedOut>
|
|
1410
|
+
* </header>
|
|
1411
|
+
* </template>
|
|
1412
|
+
* ```
|
|
1413
|
+
*/
|
|
1414
|
+
const SignedOut = (0, vue.defineComponent)({
|
|
1415
|
+
name: "SignedOut",
|
|
1416
|
+
setup(_, { slots }) {
|
|
1417
|
+
const { isAuthenticated, isLoading } = require_useAuthOS.useAuthOS();
|
|
1418
|
+
return () => {
|
|
1419
|
+
if (isLoading.value) return null;
|
|
1420
|
+
if (isAuthenticated.value) return null;
|
|
1421
|
+
return slots.default?.();
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1382
1424
|
});
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1425
|
+
//#endregion
|
|
1426
|
+
//#region src/components/MagicLinkSignIn.ts
|
|
1427
|
+
/**
|
|
1428
|
+
* Passwordless sign-in via magic link (email).
|
|
1429
|
+
*
|
|
1430
|
+
* Sends a one-time login link to the user's email address.
|
|
1431
|
+
*
|
|
1432
|
+
* @example
|
|
1433
|
+
* ```vue
|
|
1434
|
+
* <script setup>
|
|
1435
|
+
* import { MagicLinkSignIn } from '@drmhse/authos-vue';
|
|
1436
|
+
* <\/script>
|
|
1437
|
+
*
|
|
1438
|
+
* <template>
|
|
1439
|
+
* <MagicLinkSignIn @success="() => alert('Check your email!')" />
|
|
1440
|
+
* </template>
|
|
1441
|
+
* ```
|
|
1442
|
+
*/
|
|
1443
|
+
const MagicLinkSignIn = (0, vue.defineComponent)({
|
|
1444
|
+
name: "MagicLinkSignIn",
|
|
1445
|
+
props: { showPasswordSignIn: {
|
|
1446
|
+
type: Boolean,
|
|
1447
|
+
default: true
|
|
1448
|
+
} },
|
|
1449
|
+
emits: ["success", "error"],
|
|
1450
|
+
setup(props, { emit, slots }) {
|
|
1451
|
+
const { client } = require_useAuthOS.useAuthOS();
|
|
1452
|
+
const email = (0, vue.ref)("");
|
|
1453
|
+
const isLoading = (0, vue.ref)(false);
|
|
1454
|
+
const error = (0, vue.ref)(null);
|
|
1455
|
+
const isSent = (0, vue.ref)(false);
|
|
1456
|
+
async function handleSubmit() {
|
|
1457
|
+
error.value = null;
|
|
1458
|
+
isLoading.value = true;
|
|
1459
|
+
try {
|
|
1460
|
+
await client.magicLinks.request({ email: email.value });
|
|
1461
|
+
isSent.value = true;
|
|
1462
|
+
emit("success");
|
|
1463
|
+
} catch (err) {
|
|
1464
|
+
error.value = err instanceof Error ? err.message : "Failed to send magic link";
|
|
1465
|
+
emit("error", err);
|
|
1466
|
+
} finally {
|
|
1467
|
+
isLoading.value = false;
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
const slotProps = (0, vue.computed)(() => ({
|
|
1471
|
+
email: email.value,
|
|
1472
|
+
isLoading: isLoading.value,
|
|
1473
|
+
error: error.value,
|
|
1474
|
+
isSent: isSent.value,
|
|
1475
|
+
updateEmail: (val) => {
|
|
1476
|
+
email.value = val;
|
|
1477
|
+
},
|
|
1478
|
+
submit: handleSubmit,
|
|
1479
|
+
reset: () => {
|
|
1480
|
+
isSent.value = false;
|
|
1481
|
+
}
|
|
1482
|
+
}));
|
|
1483
|
+
return () => {
|
|
1484
|
+
if (slots.default) return slots.default(slotProps.value);
|
|
1485
|
+
if (isSent.value) return (0, vue.h)("div", {
|
|
1486
|
+
"data-authos-magic-link": "",
|
|
1487
|
+
"data-state": "sent"
|
|
1488
|
+
}, [(0, vue.h)("div", { "data-authos-success": "" }, [(0, vue.h)("p", "Check your email!"), (0, vue.h)("p", ["We sent a login link to ", (0, vue.h)("strong", email.value)])]), (0, vue.h)("button", {
|
|
1489
|
+
type: "button",
|
|
1490
|
+
onClick: () => {
|
|
1491
|
+
isSent.value = false;
|
|
1492
|
+
},
|
|
1493
|
+
"data-authos-back": ""
|
|
1494
|
+
}, "Use a different email")]);
|
|
1495
|
+
return (0, vue.h)("form", {
|
|
1496
|
+
onSubmit: (e) => {
|
|
1497
|
+
e.preventDefault();
|
|
1498
|
+
handleSubmit();
|
|
1499
|
+
},
|
|
1500
|
+
"data-authos-magic-link": "",
|
|
1501
|
+
"data-state": "form"
|
|
1502
|
+
}, [
|
|
1503
|
+
(0, vue.h)("div", { "data-authos-field": "email" }, [(0, vue.h)("label", { for: "authos-magic-email" }, "Email"), (0, vue.h)("input", {
|
|
1504
|
+
id: "authos-magic-email",
|
|
1505
|
+
type: "email",
|
|
1506
|
+
autocomplete: "email",
|
|
1507
|
+
value: email.value,
|
|
1508
|
+
onInput: (e) => {
|
|
1509
|
+
email.value = e.target.value;
|
|
1510
|
+
},
|
|
1511
|
+
placeholder: "Enter your email",
|
|
1512
|
+
required: true,
|
|
1513
|
+
disabled: isLoading.value
|
|
1514
|
+
})]),
|
|
1515
|
+
error.value ? (0, vue.h)("div", { "data-authos-error": "" }, error.value) : null,
|
|
1516
|
+
(0, vue.h)("button", {
|
|
1517
|
+
type: "submit",
|
|
1518
|
+
disabled: isLoading.value,
|
|
1519
|
+
"data-authos-submit": ""
|
|
1520
|
+
}, isLoading.value ? "Sending..." : "Send Magic Link"),
|
|
1521
|
+
props.showPasswordSignIn ? (0, vue.h)("div", { "data-authos-signin-prompt": "" }, [(0, vue.h)("a", {
|
|
1522
|
+
href: "/signin",
|
|
1523
|
+
"data-authos-link": "signin"
|
|
1524
|
+
}, "Sign in with password")]) : null
|
|
1525
|
+
]);
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1480
1528
|
});
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1529
|
+
//#endregion
|
|
1530
|
+
//#region src/components/PasskeySignIn.ts
|
|
1531
|
+
/**
|
|
1532
|
+
* Passkey (WebAuthn) sign-in component.
|
|
1533
|
+
*
|
|
1534
|
+
* Uses the Web Authentication API for passwordless authentication
|
|
1535
|
+
* via biometrics, security keys, or platform authenticators.
|
|
1536
|
+
*
|
|
1537
|
+
* @example
|
|
1538
|
+
* ```vue
|
|
1539
|
+
* <script setup>
|
|
1540
|
+
* import { PasskeySignIn } from '@drmhse/authos-vue';
|
|
1541
|
+
* <\/script>
|
|
1542
|
+
*
|
|
1543
|
+
* <template>
|
|
1544
|
+
* <PasskeySignIn @success="() => router.push('/dashboard')" />
|
|
1545
|
+
* </template>
|
|
1546
|
+
* ```
|
|
1547
|
+
*/
|
|
1548
|
+
const PasskeySignIn = (0, vue.defineComponent)({
|
|
1549
|
+
name: "PasskeySignIn",
|
|
1550
|
+
props: {
|
|
1551
|
+
showPasswordSignIn: {
|
|
1552
|
+
type: Boolean,
|
|
1553
|
+
default: true
|
|
1554
|
+
},
|
|
1555
|
+
orgSlug: {
|
|
1556
|
+
type: String,
|
|
1557
|
+
default: void 0
|
|
1558
|
+
},
|
|
1559
|
+
serviceSlug: {
|
|
1560
|
+
type: String,
|
|
1561
|
+
default: void 0
|
|
1562
|
+
},
|
|
1563
|
+
redirectUri: {
|
|
1564
|
+
type: String,
|
|
1565
|
+
default: void 0
|
|
1566
|
+
},
|
|
1567
|
+
state: {
|
|
1568
|
+
type: String,
|
|
1569
|
+
default: void 0
|
|
1570
|
+
}
|
|
1571
|
+
},
|
|
1572
|
+
emits: ["success", "error"],
|
|
1573
|
+
setup(props, { emit, slots }) {
|
|
1574
|
+
const { client, options } = require_useAuthOS.useAuthOS();
|
|
1575
|
+
const email = (0, vue.ref)("");
|
|
1576
|
+
const isLoading = (0, vue.ref)(false);
|
|
1577
|
+
const error = (0, vue.ref)(null);
|
|
1578
|
+
const isSupported = (0, vue.ref)(true);
|
|
1579
|
+
(0, vue.onMounted)(() => {
|
|
1580
|
+
isSupported.value = client.passkeys.isSupported();
|
|
1581
|
+
});
|
|
1582
|
+
async function handleSubmit() {
|
|
1583
|
+
error.value = null;
|
|
1584
|
+
isLoading.value = true;
|
|
1585
|
+
try {
|
|
1586
|
+
const org = props.orgSlug ?? options.org;
|
|
1587
|
+
const service = props.serviceSlug ?? options.service;
|
|
1588
|
+
const passkeyContext = org && service ? {
|
|
1589
|
+
org_slug: org,
|
|
1590
|
+
service_slug: service,
|
|
1591
|
+
redirect_uri: props.redirectUri ?? options.redirectUri,
|
|
1592
|
+
state: props.state
|
|
1593
|
+
} : void 0;
|
|
1594
|
+
await client.passkeys.login(email.value, passkeyContext);
|
|
1595
|
+
emit("success");
|
|
1596
|
+
} catch (err) {
|
|
1597
|
+
error.value = err instanceof Error ? err.message : "Passkey authentication failed";
|
|
1598
|
+
emit("error", err);
|
|
1599
|
+
} finally {
|
|
1600
|
+
isLoading.value = false;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
const slotProps = (0, vue.computed)(() => ({
|
|
1604
|
+
email: email.value,
|
|
1605
|
+
isLoading: isLoading.value,
|
|
1606
|
+
error: error.value,
|
|
1607
|
+
isSupported: isSupported.value,
|
|
1608
|
+
updateEmail: (val) => {
|
|
1609
|
+
email.value = val;
|
|
1610
|
+
},
|
|
1611
|
+
submit: handleSubmit
|
|
1612
|
+
}));
|
|
1613
|
+
return () => {
|
|
1614
|
+
if (slots.default) return slots.default(slotProps.value);
|
|
1615
|
+
if (!isSupported.value) return (0, vue.h)("div", {
|
|
1616
|
+
"data-authos-passkey": "",
|
|
1617
|
+
"data-state": "unsupported"
|
|
1618
|
+
}, [(0, vue.h)("div", { "data-authos-error": "" }, "Passkeys are not supported in this browser."), props.showPasswordSignIn ? (0, vue.h)("a", {
|
|
1619
|
+
href: "/signin",
|
|
1620
|
+
"data-authos-link": "signin"
|
|
1621
|
+
}, "Sign in with password") : null]);
|
|
1622
|
+
return (0, vue.h)("form", {
|
|
1623
|
+
onSubmit: (e) => {
|
|
1624
|
+
e.preventDefault();
|
|
1625
|
+
handleSubmit();
|
|
1626
|
+
},
|
|
1627
|
+
"data-authos-passkey": ""
|
|
1628
|
+
}, [
|
|
1629
|
+
(0, vue.h)("div", { "data-authos-field": "email" }, [(0, vue.h)("label", { for: "authos-passkey-email" }, "Email"), (0, vue.h)("input", {
|
|
1630
|
+
id: "authos-passkey-email",
|
|
1631
|
+
type: "email",
|
|
1632
|
+
autocomplete: "email webauthn",
|
|
1633
|
+
value: email.value,
|
|
1634
|
+
onInput: (e) => {
|
|
1635
|
+
email.value = e.target.value;
|
|
1636
|
+
},
|
|
1637
|
+
placeholder: "Enter your email",
|
|
1638
|
+
required: true,
|
|
1639
|
+
disabled: isLoading.value
|
|
1640
|
+
})]),
|
|
1641
|
+
error.value ? (0, vue.h)("div", { "data-authos-error": "" }, error.value) : null,
|
|
1642
|
+
(0, vue.h)("button", {
|
|
1643
|
+
type: "submit",
|
|
1644
|
+
disabled: isLoading.value,
|
|
1645
|
+
"data-authos-submit": ""
|
|
1646
|
+
}, isLoading.value ? "Authenticating..." : "Sign in with Passkey"),
|
|
1647
|
+
props.showPasswordSignIn ? (0, vue.h)("div", { "data-authos-signin-prompt": "" }, [(0, vue.h)("a", {
|
|
1648
|
+
href: "/signin",
|
|
1649
|
+
"data-authos-link": "signin"
|
|
1650
|
+
}, "Sign in with password")]) : null
|
|
1651
|
+
]);
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1570
1654
|
});
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
return vue.h("div", { "data-authos-callback": "" }, [
|
|
1637
|
-
error.value ? vue.h("div", { "data-authos-error": "" }, error.value) : vue.h("div", { "data-authos-loading": "" }, "Completing sign in...")
|
|
1638
|
-
]);
|
|
1639
|
-
};
|
|
1640
|
-
}
|
|
1655
|
+
//#endregion
|
|
1656
|
+
//#region src/components/Callback.ts
|
|
1657
|
+
const Callback = (0, vue.defineComponent)({
|
|
1658
|
+
name: "Callback",
|
|
1659
|
+
props: {
|
|
1660
|
+
onSuccess: {
|
|
1661
|
+
type: Function,
|
|
1662
|
+
default: void 0
|
|
1663
|
+
},
|
|
1664
|
+
onError: {
|
|
1665
|
+
type: Function,
|
|
1666
|
+
default: void 0
|
|
1667
|
+
}
|
|
1668
|
+
},
|
|
1669
|
+
emits: ["success", "error"],
|
|
1670
|
+
setup(props, { slots, emit }) {
|
|
1671
|
+
const { client } = require_useAuthOS.useAuthOS();
|
|
1672
|
+
const error = (0, vue.ref)(null);
|
|
1673
|
+
(0, vue.onMounted)(async () => {
|
|
1674
|
+
if (!client) {
|
|
1675
|
+
error.value = "AuthOS client not initialized";
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
const hashParams = new URLSearchParams(window.location.hash.substring(1));
|
|
1679
|
+
const queryParams = new URLSearchParams(window.location.search);
|
|
1680
|
+
const accessToken = hashParams.get("access_token") || queryParams.get("access_token");
|
|
1681
|
+
const refreshToken = hashParams.get("refresh_token") || queryParams.get("refresh_token");
|
|
1682
|
+
const errorParam = hashParams.get("error") || queryParams.get("error");
|
|
1683
|
+
const errorDescription = hashParams.get("error_description") || queryParams.get("error_description");
|
|
1684
|
+
if (errorParam) {
|
|
1685
|
+
const msg = errorDescription || errorParam;
|
|
1686
|
+
error.value = msg;
|
|
1687
|
+
const e = new Error(msg);
|
|
1688
|
+
emit("error", e);
|
|
1689
|
+
props.onError?.(e);
|
|
1690
|
+
return;
|
|
1691
|
+
}
|
|
1692
|
+
if (accessToken) try {
|
|
1693
|
+
await client.setSession({
|
|
1694
|
+
access_token: accessToken,
|
|
1695
|
+
refresh_token: refreshToken || void 0
|
|
1696
|
+
});
|
|
1697
|
+
emit("success");
|
|
1698
|
+
props.onSuccess?.();
|
|
1699
|
+
} catch (err) {
|
|
1700
|
+
const message = err.message || "Failed to set session";
|
|
1701
|
+
error.value = message;
|
|
1702
|
+
const e = err instanceof Error ? err : new Error(message);
|
|
1703
|
+
emit("error", e);
|
|
1704
|
+
props.onError?.(e);
|
|
1705
|
+
}
|
|
1706
|
+
else {
|
|
1707
|
+
const message = "No authentication tokens found in callback URL.";
|
|
1708
|
+
error.value = message;
|
|
1709
|
+
const e = /* @__PURE__ */ new Error(message);
|
|
1710
|
+
emit("error", e);
|
|
1711
|
+
props.onError?.(e);
|
|
1712
|
+
}
|
|
1713
|
+
});
|
|
1714
|
+
return () => {
|
|
1715
|
+
const slotProps = { error: error.value };
|
|
1716
|
+
if (slots.default) return slots.default(slotProps);
|
|
1717
|
+
return (0, vue.h)("div", { "data-authos-callback": "" }, [error.value ? (0, vue.h)("div", { "data-authos-error": "" }, error.value) : (0, vue.h)("div", { "data-authos-loading": "" }, "Completing sign in...")]);
|
|
1718
|
+
};
|
|
1719
|
+
}
|
|
1641
1720
|
});
|
|
1642
|
-
|
|
1721
|
+
//#endregion
|
|
1722
|
+
exports.AUTH_OS_INJECTION_KEY = require_useAuthOS.AUTH_OS_INJECTION_KEY;
|
|
1643
1723
|
Object.defineProperty(exports, "AuthErrorCodes", {
|
|
1644
|
-
|
|
1645
|
-
|
|
1724
|
+
enumerable: true,
|
|
1725
|
+
get: function() {
|
|
1726
|
+
return _drmhse_sso_sdk.AuthErrorCodes;
|
|
1727
|
+
}
|
|
1646
1728
|
});
|
|
1729
|
+
exports.AuthOSProvider = AuthOSProvider;
|
|
1647
1730
|
Object.defineProperty(exports, "BrowserStorage", {
|
|
1648
|
-
|
|
1649
|
-
|
|
1731
|
+
enumerable: true,
|
|
1732
|
+
get: function() {
|
|
1733
|
+
return _drmhse_sso_sdk.BrowserStorage;
|
|
1734
|
+
}
|
|
1650
1735
|
});
|
|
1651
|
-
Object.defineProperty(exports, "MemoryStorage", {
|
|
1652
|
-
enumerable: true,
|
|
1653
|
-
get: function () { return ssoSdk.MemoryStorage; }
|
|
1654
|
-
});
|
|
1655
|
-
Object.defineProperty(exports, "SsoApiError", {
|
|
1656
|
-
enumerable: true,
|
|
1657
|
-
get: function () { return ssoSdk.SsoApiError; }
|
|
1658
|
-
});
|
|
1659
|
-
exports.AUTH_OS_INJECTION_KEY = AUTH_OS_INJECTION_KEY;
|
|
1660
|
-
exports.AuthOSProvider = AuthOSProvider;
|
|
1661
1736
|
exports.Callback = Callback;
|
|
1662
1737
|
exports.MagicLinkSignIn = MagicLinkSignIn;
|
|
1738
|
+
Object.defineProperty(exports, "MemoryStorage", {
|
|
1739
|
+
enumerable: true,
|
|
1740
|
+
get: function() {
|
|
1741
|
+
return _drmhse_sso_sdk.MemoryStorage;
|
|
1742
|
+
}
|
|
1743
|
+
});
|
|
1663
1744
|
exports.OAuthButton = OAuthButton;
|
|
1664
1745
|
exports.OrganizationSwitcher = OrganizationSwitcher;
|
|
1665
1746
|
exports.PasskeySignIn = PasskeySignIn;
|
|
@@ -1668,11 +1749,17 @@ exports.SignIn = SignIn;
|
|
|
1668
1749
|
exports.SignUp = SignUp;
|
|
1669
1750
|
exports.SignedIn = SignedIn;
|
|
1670
1751
|
exports.SignedOut = SignedOut;
|
|
1752
|
+
Object.defineProperty(exports, "SsoApiError", {
|
|
1753
|
+
enumerable: true,
|
|
1754
|
+
get: function() {
|
|
1755
|
+
return _drmhse_sso_sdk.SsoApiError;
|
|
1756
|
+
}
|
|
1757
|
+
});
|
|
1671
1758
|
exports.UserButton = UserButton;
|
|
1672
1759
|
exports.createAuthOS = createAuthOS;
|
|
1673
1760
|
exports.useAllPermissions = useAllPermissions;
|
|
1674
1761
|
exports.useAnyPermission = useAnyPermission;
|
|
1675
|
-
exports.useAuthOS = useAuthOS;
|
|
1762
|
+
exports.useAuthOS = require_useAuthOS.useAuthOS;
|
|
1676
1763
|
exports.useOrganization = useOrganization;
|
|
1677
1764
|
exports.usePermission = usePermission;
|
|
1678
1765
|
exports.useUser = useUser;
|