@drmhse/authos-vue 0.1.2 → 0.1.4
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 +227 -149
- package/dist/{chunk-OGRUDANK.mjs → chunk-YED35B36.mjs} +6 -1
- package/dist/index.d.mts +371 -5
- package/dist/index.d.ts +371 -5
- package/dist/index.js +355 -6
- package/dist/index.mjs +344 -8
- package/dist/nuxt.js +6 -1
- package/dist/nuxt.mjs +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ function createAuthOS(options) {
|
|
|
21
21
|
return new ssoSdk.MemoryStorage();
|
|
22
22
|
};
|
|
23
23
|
const client = new ssoSdk.SsoClient({
|
|
24
|
-
baseURL: options.
|
|
24
|
+
baseURL: options.baseURL,
|
|
25
25
|
storage: getStorage(),
|
|
26
26
|
token: options.initialToken
|
|
27
27
|
// Pass initial token if provided
|
|
@@ -43,7 +43,8 @@ function createAuthOS(options) {
|
|
|
43
43
|
});
|
|
44
44
|
const context = {
|
|
45
45
|
client,
|
|
46
|
-
state
|
|
46
|
+
state,
|
|
47
|
+
options
|
|
47
48
|
};
|
|
48
49
|
return {
|
|
49
50
|
install(app) {
|
|
@@ -83,12 +84,16 @@ function createAuthOS(options) {
|
|
|
83
84
|
function useAuthOS() {
|
|
84
85
|
const context = vue.inject(AUTH_OS_INJECTION_KEY);
|
|
85
86
|
if (!context) {
|
|
87
|
+
const defaultOptions = {
|
|
88
|
+
baseURL: "http://localhost:3001"
|
|
89
|
+
};
|
|
86
90
|
const defaultClient = new ssoSdk.SsoClient({
|
|
87
|
-
baseURL:
|
|
91
|
+
baseURL: defaultOptions.baseURL,
|
|
88
92
|
storage: new ssoSdk.MemoryStorage()
|
|
89
93
|
});
|
|
90
94
|
return {
|
|
91
95
|
client: defaultClient,
|
|
96
|
+
options: defaultOptions,
|
|
92
97
|
isLoading: vue.computed(() => false),
|
|
93
98
|
isAuthenticated: vue.computed(() => false)
|
|
94
99
|
};
|
|
@@ -97,6 +102,7 @@ function useAuthOS() {
|
|
|
97
102
|
const isAuthenticated = vue.computed(() => context.state.isAuthenticated);
|
|
98
103
|
return {
|
|
99
104
|
client: context.client,
|
|
105
|
+
options: context.options,
|
|
100
106
|
isLoading,
|
|
101
107
|
isAuthenticated
|
|
102
108
|
};
|
|
@@ -133,6 +139,11 @@ function useOrganization() {
|
|
|
133
139
|
if (!context) return;
|
|
134
140
|
isSwitching.value = true;
|
|
135
141
|
try {
|
|
142
|
+
const result = await context.client.organizations.select(slug);
|
|
143
|
+
await context.client.setSession({
|
|
144
|
+
access_token: result.access_token,
|
|
145
|
+
refresh_token: result.refresh_token
|
|
146
|
+
});
|
|
136
147
|
const orgResponse = await context.client.organizations.get(slug);
|
|
137
148
|
context.state.currentOrganization = orgResponse;
|
|
138
149
|
return orgResponse;
|
|
@@ -147,13 +158,46 @@ function useOrganization() {
|
|
|
147
158
|
isSwitching
|
|
148
159
|
};
|
|
149
160
|
}
|
|
161
|
+
function usePermission(permission) {
|
|
162
|
+
const { user } = useUser();
|
|
163
|
+
return vue.computed(() => {
|
|
164
|
+
if (!user.value || !permission) return false;
|
|
165
|
+
return user.value.permissions?.includes(permission) ?? false;
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
function useAnyPermission(permissions) {
|
|
169
|
+
const { user } = useUser();
|
|
170
|
+
return vue.computed(() => {
|
|
171
|
+
if (!user.value || permissions.length === 0) return false;
|
|
172
|
+
return permissions.some((p) => user.value?.permissions?.includes(p));
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
function useAllPermissions(permissions) {
|
|
176
|
+
const { user } = useUser();
|
|
177
|
+
return vue.computed(() => {
|
|
178
|
+
if (!user.value || permissions.length === 0) return false;
|
|
179
|
+
return permissions.every((p) => user.value?.permissions?.includes(p));
|
|
180
|
+
});
|
|
181
|
+
}
|
|
150
182
|
var AuthOSProvider = vue.defineComponent({
|
|
151
183
|
name: "AuthOSProvider",
|
|
152
184
|
props: {
|
|
153
|
-
|
|
185
|
+
baseURL: {
|
|
154
186
|
type: String,
|
|
155
187
|
required: true
|
|
156
188
|
},
|
|
189
|
+
org: {
|
|
190
|
+
type: String,
|
|
191
|
+
default: void 0
|
|
192
|
+
},
|
|
193
|
+
service: {
|
|
194
|
+
type: String,
|
|
195
|
+
default: void 0
|
|
196
|
+
},
|
|
197
|
+
redirectUri: {
|
|
198
|
+
type: String,
|
|
199
|
+
default: void 0
|
|
200
|
+
},
|
|
157
201
|
storage: {
|
|
158
202
|
type: Object,
|
|
159
203
|
default: void 0
|
|
@@ -170,7 +214,7 @@ var AuthOSProvider = vue.defineComponent({
|
|
|
170
214
|
return new ssoSdk.MemoryStorage();
|
|
171
215
|
};
|
|
172
216
|
const client = props.client ?? new ssoSdk.SsoClient({
|
|
173
|
-
baseURL: props.
|
|
217
|
+
baseURL: props.baseURL,
|
|
174
218
|
storage: getStorage()
|
|
175
219
|
});
|
|
176
220
|
const state = vue.reactive({
|
|
@@ -180,7 +224,13 @@ var AuthOSProvider = vue.defineComponent({
|
|
|
180
224
|
currentOrganization: null,
|
|
181
225
|
organizations: []
|
|
182
226
|
});
|
|
183
|
-
const
|
|
227
|
+
const options = {
|
|
228
|
+
baseURL: props.baseURL,
|
|
229
|
+
org: props.org,
|
|
230
|
+
service: props.service,
|
|
231
|
+
redirectUri: props.redirectUri
|
|
232
|
+
};
|
|
233
|
+
const context = { client, state, options };
|
|
184
234
|
vue.provide(AUTH_OS_INJECTION_KEY, context);
|
|
185
235
|
let unsubscribe;
|
|
186
236
|
vue.onMounted(() => {
|
|
@@ -545,6 +595,297 @@ var Protect = vue.defineComponent({
|
|
|
545
595
|
};
|
|
546
596
|
}
|
|
547
597
|
});
|
|
598
|
+
var PROVIDER_NAMES = {
|
|
599
|
+
github: "GitHub",
|
|
600
|
+
google: "Google",
|
|
601
|
+
microsoft: "Microsoft"
|
|
602
|
+
};
|
|
603
|
+
var OAuthButton = vue.defineComponent({
|
|
604
|
+
name: "OAuthButton",
|
|
605
|
+
props: {
|
|
606
|
+
provider: {
|
|
607
|
+
type: String,
|
|
608
|
+
required: true
|
|
609
|
+
},
|
|
610
|
+
disabled: {
|
|
611
|
+
type: Boolean,
|
|
612
|
+
default: false
|
|
613
|
+
}
|
|
614
|
+
},
|
|
615
|
+
emits: ["redirect"],
|
|
616
|
+
setup(props, { slots, emit }) {
|
|
617
|
+
const { client, options } = useAuthOS();
|
|
618
|
+
const isConfigured = vue.computed(() => !!(options.org && options.service));
|
|
619
|
+
const providerName = vue.computed(() => PROVIDER_NAMES[props.provider]);
|
|
620
|
+
function handleClick() {
|
|
621
|
+
if (!options.org || !options.service) {
|
|
622
|
+
console.error(
|
|
623
|
+
`[AuthOS] OAuth login requires "org" and "service" in createAuthOS options.
|
|
624
|
+
Current options: { org: ${options.org ? `"${options.org}"` : "undefined"}, service: ${options.service ? `"${options.service}"` : "undefined"} }
|
|
625
|
+
|
|
626
|
+
Example:
|
|
627
|
+
app.use(createAuthOS({
|
|
628
|
+
baseURL: "${options.baseURL}",
|
|
629
|
+
org: "your-org-slug",
|
|
630
|
+
service: "your-service-slug",
|
|
631
|
+
}));
|
|
632
|
+
|
|
633
|
+
See: https://docs.authos.dev/vue/oauth-setup`
|
|
634
|
+
);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
const redirectUri = options.redirectUri ?? (typeof window !== "undefined" ? window.location.origin + "/callback" : void 0);
|
|
638
|
+
const url = client.auth.getLoginUrl(props.provider, {
|
|
639
|
+
org: options.org,
|
|
640
|
+
service: options.service,
|
|
641
|
+
redirect_uri: redirectUri
|
|
642
|
+
});
|
|
643
|
+
emit("redirect");
|
|
644
|
+
window.location.href = url;
|
|
645
|
+
}
|
|
646
|
+
return () => {
|
|
647
|
+
const slotProps = {
|
|
648
|
+
provider: props.provider,
|
|
649
|
+
providerName: providerName.value,
|
|
650
|
+
isConfigured: isConfigured.value,
|
|
651
|
+
disabled: props.disabled,
|
|
652
|
+
handleClick
|
|
653
|
+
};
|
|
654
|
+
if (slots.default) {
|
|
655
|
+
return slots.default(slotProps);
|
|
656
|
+
}
|
|
657
|
+
return vue.h(
|
|
658
|
+
"button",
|
|
659
|
+
{
|
|
660
|
+
type: "button",
|
|
661
|
+
onClick: handleClick,
|
|
662
|
+
disabled: props.disabled || !isConfigured.value,
|
|
663
|
+
"data-authos-oauth": "",
|
|
664
|
+
"data-provider": props.provider
|
|
665
|
+
},
|
|
666
|
+
`Continue with ${providerName.value}`
|
|
667
|
+
);
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
var SignedIn = vue.defineComponent({
|
|
672
|
+
name: "SignedIn",
|
|
673
|
+
setup(_, { slots }) {
|
|
674
|
+
const { isAuthenticated, isLoading } = useAuthOS();
|
|
675
|
+
return () => {
|
|
676
|
+
if (isLoading.value) {
|
|
677
|
+
return null;
|
|
678
|
+
}
|
|
679
|
+
if (!isAuthenticated.value) {
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
return slots.default?.();
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
var SignedOut = vue.defineComponent({
|
|
687
|
+
name: "SignedOut",
|
|
688
|
+
setup(_, { slots }) {
|
|
689
|
+
const { isAuthenticated, isLoading } = useAuthOS();
|
|
690
|
+
return () => {
|
|
691
|
+
if (isLoading.value) {
|
|
692
|
+
return null;
|
|
693
|
+
}
|
|
694
|
+
if (isAuthenticated.value) {
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
return slots.default?.();
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
var MagicLinkSignIn = vue.defineComponent({
|
|
702
|
+
name: "MagicLinkSignIn",
|
|
703
|
+
props: {
|
|
704
|
+
showPasswordSignIn: {
|
|
705
|
+
type: Boolean,
|
|
706
|
+
default: true
|
|
707
|
+
}
|
|
708
|
+
},
|
|
709
|
+
emits: ["success", "error"],
|
|
710
|
+
setup(props, { emit, slots }) {
|
|
711
|
+
const { client } = useAuthOS();
|
|
712
|
+
const email = vue.ref("");
|
|
713
|
+
const isLoading = vue.ref(false);
|
|
714
|
+
const error = vue.ref(null);
|
|
715
|
+
const isSent = vue.ref(false);
|
|
716
|
+
async function handleSubmit() {
|
|
717
|
+
error.value = null;
|
|
718
|
+
isLoading.value = true;
|
|
719
|
+
try {
|
|
720
|
+
await client.magicLinks.request({ email: email.value });
|
|
721
|
+
isSent.value = true;
|
|
722
|
+
emit("success");
|
|
723
|
+
} catch (err) {
|
|
724
|
+
const message = err instanceof Error ? err.message : "Failed to send magic link";
|
|
725
|
+
error.value = message;
|
|
726
|
+
emit("error", err);
|
|
727
|
+
} finally {
|
|
728
|
+
isLoading.value = false;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
const slotProps = vue.computed(() => ({
|
|
732
|
+
email: email.value,
|
|
733
|
+
isLoading: isLoading.value,
|
|
734
|
+
error: error.value,
|
|
735
|
+
isSent: isSent.value,
|
|
736
|
+
updateEmail: (val) => {
|
|
737
|
+
email.value = val;
|
|
738
|
+
},
|
|
739
|
+
submit: handleSubmit,
|
|
740
|
+
reset: () => {
|
|
741
|
+
isSent.value = false;
|
|
742
|
+
}
|
|
743
|
+
}));
|
|
744
|
+
return () => {
|
|
745
|
+
if (slots.default) {
|
|
746
|
+
return slots.default(slotProps.value);
|
|
747
|
+
}
|
|
748
|
+
if (isSent.value) {
|
|
749
|
+
return vue.h("div", { "data-authos-magic-link": "", "data-state": "sent" }, [
|
|
750
|
+
vue.h("div", { "data-authos-success": "" }, [
|
|
751
|
+
vue.h("p", "Check your email!"),
|
|
752
|
+
vue.h("p", ["We sent a login link to ", vue.h("strong", email.value)])
|
|
753
|
+
]),
|
|
754
|
+
vue.h("button", {
|
|
755
|
+
type: "button",
|
|
756
|
+
onClick: () => {
|
|
757
|
+
isSent.value = false;
|
|
758
|
+
},
|
|
759
|
+
"data-authos-back": ""
|
|
760
|
+
}, "Use a different email")
|
|
761
|
+
]);
|
|
762
|
+
}
|
|
763
|
+
return vue.h("form", {
|
|
764
|
+
onSubmit: (e) => {
|
|
765
|
+
e.preventDefault();
|
|
766
|
+
handleSubmit();
|
|
767
|
+
},
|
|
768
|
+
"data-authos-magic-link": "",
|
|
769
|
+
"data-state": "form"
|
|
770
|
+
}, [
|
|
771
|
+
vue.h("div", { "data-authos-field": "email" }, [
|
|
772
|
+
vue.h("label", { for: "authos-magic-email" }, "Email"),
|
|
773
|
+
vue.h("input", {
|
|
774
|
+
id: "authos-magic-email",
|
|
775
|
+
type: "email",
|
|
776
|
+
autocomplete: "email",
|
|
777
|
+
value: email.value,
|
|
778
|
+
onInput: (e) => {
|
|
779
|
+
email.value = e.target.value;
|
|
780
|
+
},
|
|
781
|
+
placeholder: "Enter your email",
|
|
782
|
+
required: true,
|
|
783
|
+
disabled: isLoading.value
|
|
784
|
+
})
|
|
785
|
+
]),
|
|
786
|
+
error.value ? vue.h("div", { "data-authos-error": "" }, error.value) : null,
|
|
787
|
+
vue.h("button", {
|
|
788
|
+
type: "submit",
|
|
789
|
+
disabled: isLoading.value,
|
|
790
|
+
"data-authos-submit": ""
|
|
791
|
+
}, isLoading.value ? "Sending..." : "Send Magic Link"),
|
|
792
|
+
props.showPasswordSignIn ? vue.h("div", { "data-authos-signin-prompt": "" }, [
|
|
793
|
+
vue.h("a", { href: "/signin", "data-authos-link": "signin" }, "Sign in with password")
|
|
794
|
+
]) : null
|
|
795
|
+
]);
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
var PasskeySignIn = vue.defineComponent({
|
|
800
|
+
name: "PasskeySignIn",
|
|
801
|
+
props: {
|
|
802
|
+
showPasswordSignIn: {
|
|
803
|
+
type: Boolean,
|
|
804
|
+
default: true
|
|
805
|
+
}
|
|
806
|
+
},
|
|
807
|
+
emits: ["success", "error"],
|
|
808
|
+
setup(props, { emit, slots }) {
|
|
809
|
+
const { client } = useAuthOS();
|
|
810
|
+
const email = vue.ref("");
|
|
811
|
+
const isLoading = vue.ref(false);
|
|
812
|
+
const error = vue.ref(null);
|
|
813
|
+
const isSupported = vue.ref(true);
|
|
814
|
+
vue.onMounted(() => {
|
|
815
|
+
isSupported.value = client.passkeys.isSupported();
|
|
816
|
+
});
|
|
817
|
+
async function handleSubmit() {
|
|
818
|
+
error.value = null;
|
|
819
|
+
isLoading.value = true;
|
|
820
|
+
try {
|
|
821
|
+
await client.passkeys.login(email.value);
|
|
822
|
+
emit("success");
|
|
823
|
+
} catch (err) {
|
|
824
|
+
const message = err instanceof Error ? err.message : "Passkey authentication failed";
|
|
825
|
+
error.value = message;
|
|
826
|
+
emit("error", err);
|
|
827
|
+
} finally {
|
|
828
|
+
isLoading.value = false;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
const slotProps = vue.computed(() => ({
|
|
832
|
+
email: email.value,
|
|
833
|
+
isLoading: isLoading.value,
|
|
834
|
+
error: error.value,
|
|
835
|
+
isSupported: isSupported.value,
|
|
836
|
+
updateEmail: (val) => {
|
|
837
|
+
email.value = val;
|
|
838
|
+
},
|
|
839
|
+
submit: handleSubmit
|
|
840
|
+
}));
|
|
841
|
+
return () => {
|
|
842
|
+
if (slots.default) {
|
|
843
|
+
return slots.default(slotProps.value);
|
|
844
|
+
}
|
|
845
|
+
if (!isSupported.value) {
|
|
846
|
+
return vue.h("div", {
|
|
847
|
+
"data-authos-passkey": "",
|
|
848
|
+
"data-state": "unsupported"
|
|
849
|
+
}, [
|
|
850
|
+
vue.h("div", { "data-authos-error": "" }, "Passkeys are not supported in this browser."),
|
|
851
|
+
props.showPasswordSignIn ? vue.h("a", { href: "/signin", "data-authos-link": "signin" }, "Sign in with password") : null
|
|
852
|
+
]);
|
|
853
|
+
}
|
|
854
|
+
return vue.h("form", {
|
|
855
|
+
onSubmit: (e) => {
|
|
856
|
+
e.preventDefault();
|
|
857
|
+
handleSubmit();
|
|
858
|
+
},
|
|
859
|
+
"data-authos-passkey": ""
|
|
860
|
+
}, [
|
|
861
|
+
vue.h("div", { "data-authos-field": "email" }, [
|
|
862
|
+
vue.h("label", { for: "authos-passkey-email" }, "Email"),
|
|
863
|
+
vue.h("input", {
|
|
864
|
+
id: "authos-passkey-email",
|
|
865
|
+
type: "email",
|
|
866
|
+
autocomplete: "email webauthn",
|
|
867
|
+
value: email.value,
|
|
868
|
+
onInput: (e) => {
|
|
869
|
+
email.value = e.target.value;
|
|
870
|
+
},
|
|
871
|
+
placeholder: "Enter your email",
|
|
872
|
+
required: true,
|
|
873
|
+
disabled: isLoading.value
|
|
874
|
+
})
|
|
875
|
+
]),
|
|
876
|
+
error.value ? vue.h("div", { "data-authos-error": "" }, error.value) : null,
|
|
877
|
+
vue.h("button", {
|
|
878
|
+
type: "submit",
|
|
879
|
+
disabled: isLoading.value,
|
|
880
|
+
"data-authos-submit": ""
|
|
881
|
+
}, isLoading.value ? "Authenticating..." : "Sign in with Passkey"),
|
|
882
|
+
props.showPasswordSignIn ? vue.h("div", { "data-authos-signin-prompt": "" }, [
|
|
883
|
+
vue.h("a", { href: "/signin", "data-authos-link": "signin" }, "Sign in with password")
|
|
884
|
+
]) : null
|
|
885
|
+
]);
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
});
|
|
548
889
|
|
|
549
890
|
Object.defineProperty(exports, "AuthErrorCodes", {
|
|
550
891
|
enumerable: true,
|
|
@@ -564,12 +905,20 @@ Object.defineProperty(exports, "SsoApiError", {
|
|
|
564
905
|
});
|
|
565
906
|
exports.AUTH_OS_INJECTION_KEY = AUTH_OS_INJECTION_KEY;
|
|
566
907
|
exports.AuthOSProvider = AuthOSProvider;
|
|
908
|
+
exports.MagicLinkSignIn = MagicLinkSignIn;
|
|
909
|
+
exports.OAuthButton = OAuthButton;
|
|
567
910
|
exports.OrganizationSwitcher = OrganizationSwitcher;
|
|
911
|
+
exports.PasskeySignIn = PasskeySignIn;
|
|
568
912
|
exports.Protect = Protect;
|
|
569
913
|
exports.SignIn = SignIn;
|
|
570
914
|
exports.SignUp = SignUp;
|
|
915
|
+
exports.SignedIn = SignedIn;
|
|
916
|
+
exports.SignedOut = SignedOut;
|
|
571
917
|
exports.UserButton = UserButton;
|
|
572
918
|
exports.createAuthOS = createAuthOS;
|
|
919
|
+
exports.useAllPermissions = useAllPermissions;
|
|
920
|
+
exports.useAnyPermission = useAnyPermission;
|
|
573
921
|
exports.useAuthOS = useAuthOS;
|
|
574
922
|
exports.useOrganization = useOrganization;
|
|
923
|
+
exports.usePermission = usePermission;
|
|
575
924
|
exports.useUser = useUser;
|