@drmhse/authos-react 0.1.3 → 0.1.5

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.js CHANGED
@@ -50,6 +50,7 @@ function AuthOSProvider({ config, children, client: externalClient, initialSessi
50
50
  const contextValue = react.useMemo(
51
51
  () => ({
52
52
  client,
53
+ config,
53
54
  user,
54
55
  isAuthenticated: !!user,
55
56
  isLoading,
@@ -58,7 +59,7 @@ function AuthOSProvider({ config, children, client: externalClient, initialSessi
58
59
  setOrganization,
59
60
  refreshUser
60
61
  }),
61
- [client, user, isLoading, organization, refreshUser]
62
+ [client, config, user, isLoading, organization, refreshUser]
62
63
  );
63
64
  return /* @__PURE__ */ jsxRuntime.jsx(AuthOSContext.Provider, { value: contextValue, children });
64
65
  }
@@ -85,8 +86,12 @@ function useOrganization() {
85
86
  const { client, organization, setOrganization, refreshUser } = useAuthOSContext();
86
87
  const switchOrganization = react.useCallback(
87
88
  async (slug) => {
88
- const orgResponse = await client.organizations.get(slug);
89
- setOrganization(orgResponse.organization);
89
+ const result = await client.organizations.select(slug);
90
+ await client.setSession({
91
+ access_token: result.access_token,
92
+ refresh_token: result.refresh_token
93
+ });
94
+ setOrganization(result.organization);
90
95
  await refreshUser();
91
96
  },
92
97
  [client, setOrganization, refreshUser]
@@ -114,15 +119,71 @@ function useAllPermissions(permissions) {
114
119
  return permissions.every((perm) => user.permissions.includes(perm));
115
120
  }, [user?.permissions, permissions]);
116
121
  }
122
+ var PROVIDER_NAMES = {
123
+ github: "GitHub",
124
+ google: "Google",
125
+ microsoft: "Microsoft"
126
+ };
127
+ function OAuthButton({
128
+ provider,
129
+ children,
130
+ className,
131
+ onRedirect,
132
+ disabled = false
133
+ }) {
134
+ const { client, config } = useAuthOSContext();
135
+ const handleClick = react.useCallback(() => {
136
+ if (!config.org || !config.service) {
137
+ console.error(
138
+ `[AuthOS] OAuth login requires "org" and "service" in AuthOSProvider config.
139
+ Current config: { org: ${config.org ? `"${config.org}"` : "undefined"}, service: ${config.service ? `"${config.service}"` : "undefined"} }
140
+
141
+ Example:
142
+ <AuthOSProvider config={{
143
+ baseURL: "${config.baseURL}",
144
+ org: "your-org-slug",
145
+ service: "your-service-slug",
146
+ }}>
147
+
148
+ See: https://docs.authos.dev/react/oauth-setup`
149
+ );
150
+ return;
151
+ }
152
+ const redirectUri = config.redirectUri ?? (typeof window !== "undefined" ? window.location.origin + "/callback" : void 0);
153
+ const url = client.auth.getLoginUrl(provider, {
154
+ org: config.org,
155
+ service: config.service,
156
+ redirect_uri: redirectUri
157
+ });
158
+ onRedirect?.();
159
+ window.location.href = url;
160
+ }, [client, config, provider, onRedirect]);
161
+ return /* @__PURE__ */ jsxRuntime.jsx(
162
+ "button",
163
+ {
164
+ type: "button",
165
+ onClick: handleClick,
166
+ className,
167
+ disabled,
168
+ "data-authos-oauth": "",
169
+ "data-provider": provider,
170
+ children: children ?? `Continue with ${PROVIDER_NAMES[provider]}`
171
+ }
172
+ );
173
+ }
117
174
  var MFA_PREAUTH_EXPIRY = 300;
118
175
  function SignIn({
119
176
  onSuccess,
120
177
  onError,
121
178
  showForgotPassword = true,
122
179
  showSignUp = true,
123
- className
180
+ className,
181
+ providers = false,
182
+ showDivider = true
124
183
  }) {
125
- const { client, setUser } = useAuthOSContext();
184
+ const { client, config, setUser } = useAuthOSContext();
185
+ const hasOAuthConfig = !!(config.org && config.service);
186
+ const oauthProviders = providers && Array.isArray(providers) ? providers : [];
126
187
  const [state, setState] = react.useState("credentials");
127
188
  const [email, setEmail] = react.useState("");
128
189
  const [password, setPassword] = react.useState("");
@@ -136,7 +197,12 @@ function SignIn({
136
197
  setError(null);
137
198
  setIsLoading(true);
138
199
  try {
139
- const result = await client.auth.login({ email, password });
200
+ const result = await client.auth.login({
201
+ email,
202
+ password,
203
+ org_slug: config.org,
204
+ service_slug: config.service
205
+ });
140
206
  if (result.expires_in === MFA_PREAUTH_EXPIRY) {
141
207
  setPreauthToken(result.access_token);
142
208
  setState("mfa");
@@ -153,7 +219,7 @@ function SignIn({
153
219
  setIsLoading(false);
154
220
  }
155
221
  },
156
- [client, email, password, setUser, onSuccess, onError]
222
+ [client, email, password, config.org, config.service, setUser, onSuccess, onError]
157
223
  );
158
224
  const handleMfaSubmit = react.useCallback(
159
225
  async (e) => {
@@ -205,49 +271,63 @@ function SignIn({
205
271
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: handleBackToCredentials, "data-authos-back": "", children: "Back to login" })
206
272
  ] }) });
207
273
  }
208
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-authos-signin": "", "data-state": "credentials", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleCredentialsSubmit, children: [
209
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-field": "email", children: [
210
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "authos-email", children: "Email" }),
211
- /* @__PURE__ */ jsxRuntime.jsx(
212
- "input",
213
- {
214
- id: "authos-email",
215
- type: "email",
216
- autoComplete: "email",
217
- value: email,
218
- onChange: (e) => setEmail(e.target.value),
219
- placeholder: "Enter your email",
220
- required: true,
221
- disabled: isLoading
222
- }
223
- )
224
- ] }),
225
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-field": "password", children: [
226
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "authos-password", children: "Password" }),
227
- /* @__PURE__ */ jsxRuntime.jsx(
228
- "input",
274
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-authos-signin": "", "data-state": "credentials", children: [
275
+ oauthProviders.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-oauth-section": "", children: [
276
+ oauthProviders.map((provider) => /* @__PURE__ */ jsxRuntime.jsx(
277
+ OAuthButton,
229
278
  {
230
- id: "authos-password",
231
- type: "password",
232
- autoComplete: "current-password",
233
- value: password,
234
- onChange: (e) => setPassword(e.target.value),
235
- placeholder: "Enter your password",
236
- required: true,
237
- disabled: isLoading
238
- }
239
- )
279
+ provider,
280
+ disabled: isLoading || !hasOAuthConfig
281
+ },
282
+ provider
283
+ )),
284
+ !hasOAuthConfig && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-authos-oauth-warning": "", style: { color: "orange", fontSize: "0.875rem" }, children: "OAuth requires org and service in AuthOSProvider config" })
240
285
  ] }),
241
- error && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-authos-error": true, children: error }),
242
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: isLoading, "data-authos-submit": "", children: isLoading ? "Signing in..." : "Sign In" }),
243
- showForgotPassword && /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/forgot-password", "data-authos-link": "forgot-password", children: "Forgot password?" }),
244
- showSignUp && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-signup-prompt": true, children: [
245
- "Don't have an account? ",
246
- /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/signup", "data-authos-link": "signup", children: "Sign up" })
286
+ oauthProviders.length > 0 && showDivider && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-authos-divider": "", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: "or" }) }),
287
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleCredentialsSubmit, children: [
288
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-field": "email", children: [
289
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "authos-email", children: "Email" }),
290
+ /* @__PURE__ */ jsxRuntime.jsx(
291
+ "input",
292
+ {
293
+ id: "authos-email",
294
+ type: "email",
295
+ autoComplete: "email",
296
+ value: email,
297
+ onChange: (e) => setEmail(e.target.value),
298
+ placeholder: "Enter your email",
299
+ required: true,
300
+ disabled: isLoading
301
+ }
302
+ )
303
+ ] }),
304
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-field": "password", children: [
305
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "authos-password", children: "Password" }),
306
+ /* @__PURE__ */ jsxRuntime.jsx(
307
+ "input",
308
+ {
309
+ id: "authos-password",
310
+ type: "password",
311
+ autoComplete: "current-password",
312
+ value: password,
313
+ onChange: (e) => setPassword(e.target.value),
314
+ placeholder: "Enter your password",
315
+ required: true,
316
+ disabled: isLoading
317
+ }
318
+ )
319
+ ] }),
320
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-authos-error": true, children: error }),
321
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: isLoading, "data-authos-submit": "", children: isLoading ? "Signing in..." : "Sign In" }),
322
+ showForgotPassword && /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/forgot-password", "data-authos-link": "forgot-password", children: "Forgot password?" }),
323
+ showSignUp && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-signup-prompt": true, children: [
324
+ "Don't have an account? ",
325
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/signup", "data-authos-link": "signup", children: "Sign up" })
326
+ ] })
247
327
  ] })
248
- ] }) });
328
+ ] });
249
329
  }
250
- function SignUp({ onSuccess, onError, orgSlug, showSignIn = true, className }) {
330
+ function SignUp({ onSuccess, onError, orgSlug, serviceSlug, showSignIn = true, className }) {
251
331
  const { client } = useAuthOSContext();
252
332
  const [email, setEmail] = react.useState("");
253
333
  const [password, setPassword] = react.useState("");
@@ -272,7 +352,8 @@ function SignUp({ onSuccess, onError, orgSlug, showSignIn = true, className }) {
272
352
  await client.auth.register({
273
353
  email,
274
354
  password,
275
- org_slug: orgSlug
355
+ org_slug: orgSlug,
356
+ service_slug: serviceSlug
276
357
  });
277
358
  setIsSuccess(true);
278
359
  onSuccess?.();
@@ -284,7 +365,7 @@ function SignUp({ onSuccess, onError, orgSlug, showSignIn = true, className }) {
284
365
  setIsLoading(false);
285
366
  }
286
367
  },
287
- [client, email, password, confirmPassword, orgSlug, onSuccess, onError]
368
+ [client, email, password, confirmPassword, orgSlug, serviceSlug, onSuccess, onError]
288
369
  );
289
370
  if (isSuccess) {
290
371
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-authos-signup": true, "data-state": "success", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-success": true, children: [
@@ -534,6 +615,160 @@ function Protect({ permission, role, fallback = null, children }) {
534
615
  };
535
616
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-authos-protect": true, children: renderContent() });
536
617
  }
618
+ function SignedIn({ children }) {
619
+ const { isAuthenticated, isLoading } = useAuthOSContext();
620
+ if (isLoading) {
621
+ return null;
622
+ }
623
+ if (!isAuthenticated) {
624
+ return null;
625
+ }
626
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
627
+ }
628
+ function SignedOut({ children }) {
629
+ const { isAuthenticated, isLoading } = useAuthOSContext();
630
+ if (isLoading) {
631
+ return null;
632
+ }
633
+ if (isAuthenticated) {
634
+ return null;
635
+ }
636
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
637
+ }
638
+ function MagicLinkSignIn({
639
+ onSuccess,
640
+ onError,
641
+ className,
642
+ showPasswordSignIn = true
643
+ }) {
644
+ const { client } = useAuthOSContext();
645
+ const [email, setEmail] = react.useState("");
646
+ const [isLoading, setIsLoading] = react.useState(false);
647
+ const [error, setError] = react.useState(null);
648
+ const [isSent, setIsSent] = react.useState(false);
649
+ const handleSubmit = react.useCallback(
650
+ async (e) => {
651
+ e.preventDefault();
652
+ setError(null);
653
+ setIsLoading(true);
654
+ try {
655
+ await client.magicLinks.request({ email });
656
+ setIsSent(true);
657
+ onSuccess?.();
658
+ } catch (err) {
659
+ const message = err instanceof ssoSdk.SsoApiError ? err.message : "Failed to send magic link";
660
+ setError(message);
661
+ onError?.(err instanceof Error ? err : new Error(message));
662
+ } finally {
663
+ setIsLoading(false);
664
+ }
665
+ },
666
+ [client, email, onSuccess, onError]
667
+ );
668
+ if (isSent) {
669
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-authos-magic-link": "", "data-state": "sent", children: [
670
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-success": "", children: [
671
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Check your email!" }),
672
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
673
+ "We sent a login link to ",
674
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: email })
675
+ ] })
676
+ ] }),
677
+ /* @__PURE__ */ jsxRuntime.jsx(
678
+ "button",
679
+ {
680
+ type: "button",
681
+ onClick: () => setIsSent(false),
682
+ "data-authos-back": "",
683
+ children: "Use a different email"
684
+ }
685
+ )
686
+ ] });
687
+ }
688
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-authos-magic-link": "", "data-state": "form", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, children: [
689
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-field": "email", children: [
690
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "authos-magic-email", children: "Email" }),
691
+ /* @__PURE__ */ jsxRuntime.jsx(
692
+ "input",
693
+ {
694
+ id: "authos-magic-email",
695
+ type: "email",
696
+ autoComplete: "email",
697
+ value: email,
698
+ onChange: (e) => setEmail(e.target.value),
699
+ placeholder: "Enter your email",
700
+ required: true,
701
+ disabled: isLoading
702
+ }
703
+ )
704
+ ] }),
705
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-authos-error": "", children: error }),
706
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: isLoading, "data-authos-submit": "", children: isLoading ? "Sending..." : "Send Magic Link" }),
707
+ showPasswordSignIn && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-authos-signin-prompt": "", children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/signin", "data-authos-link": "signin", children: "Sign in with password" }) })
708
+ ] }) });
709
+ }
710
+ function PasskeySignIn({
711
+ onSuccess,
712
+ onError,
713
+ className,
714
+ showPasswordSignIn = true
715
+ }) {
716
+ const { client, setUser } = useAuthOSContext();
717
+ const [email, setEmail] = react.useState("");
718
+ const [isLoading, setIsLoading] = react.useState(false);
719
+ const [error, setError] = react.useState(null);
720
+ const [isSupported, setIsSupported] = react.useState(true);
721
+ react.useEffect(() => {
722
+ setIsSupported(client.passkeys.isSupported());
723
+ }, [client]);
724
+ const handleSubmit = react.useCallback(
725
+ async (e) => {
726
+ e.preventDefault();
727
+ setError(null);
728
+ setIsLoading(true);
729
+ try {
730
+ await client.passkeys.login(email);
731
+ const profile = await client.user.getProfile();
732
+ setUser(profile);
733
+ onSuccess?.();
734
+ } catch (err) {
735
+ const message = err instanceof ssoSdk.SsoApiError ? err.message : err instanceof Error ? err.message : "Passkey authentication failed";
736
+ setError(message);
737
+ onError?.(err instanceof Error ? err : new Error(message));
738
+ } finally {
739
+ setIsLoading(false);
740
+ }
741
+ },
742
+ [client, email, setUser, onSuccess, onError]
743
+ );
744
+ if (!isSupported) {
745
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-authos-passkey": "", "data-state": "unsupported", children: [
746
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-authos-error": "", children: "Passkeys are not supported in this browser." }),
747
+ showPasswordSignIn && /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/signin", "data-authos-link": "signin", children: "Sign in with password" })
748
+ ] });
749
+ }
750
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-authos-passkey": "", children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, children: [
751
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-authos-field": "email", children: [
752
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "authos-passkey-email", children: "Email" }),
753
+ /* @__PURE__ */ jsxRuntime.jsx(
754
+ "input",
755
+ {
756
+ id: "authos-passkey-email",
757
+ type: "email",
758
+ autoComplete: "email webauthn",
759
+ value: email,
760
+ onChange: (e) => setEmail(e.target.value),
761
+ placeholder: "Enter your email",
762
+ required: true,
763
+ disabled: isLoading
764
+ }
765
+ )
766
+ ] }),
767
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-authos-error": "", children: error }),
768
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", disabled: isLoading, "data-authos-submit": "", children: isLoading ? "Authenticating..." : "Sign in with Passkey" }),
769
+ showPasswordSignIn && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-authos-signin-prompt": "", children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/signin", "data-authos-link": "signin", children: "Sign in with password" }) })
770
+ ] }) });
771
+ }
537
772
 
538
773
  Object.defineProperty(exports, "AuthErrorCodes", {
539
774
  enumerable: true,
@@ -548,10 +783,15 @@ Object.defineProperty(exports, "SsoClient", {
548
783
  get: function () { return ssoSdk.SsoClient; }
549
784
  });
550
785
  exports.AuthOSProvider = AuthOSProvider;
786
+ exports.MagicLinkSignIn = MagicLinkSignIn;
787
+ exports.OAuthButton = OAuthButton;
551
788
  exports.OrganizationSwitcher = OrganizationSwitcher;
789
+ exports.PasskeySignIn = PasskeySignIn;
552
790
  exports.Protect = Protect;
553
791
  exports.SignIn = SignIn;
554
792
  exports.SignUp = SignUp;
793
+ exports.SignedIn = SignedIn;
794
+ exports.SignedOut = SignedOut;
555
795
  exports.UserButton = UserButton;
556
796
  exports.useAllPermissions = useAllPermissions;
557
797
  exports.useAnyPermission = useAnyPermission;