@object-ui/auth 13.1.0 → 14.0.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # @object-ui/auth
2
2
 
3
+ ## 14.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 94d00d4: feat(auth): phone number + password sign-in on the login page
8
+
9
+ The login page's password mode now accepts an **email OR a phone number** as the
10
+ identifier and routes by shape — email → `/sign-in/email`, phone →
11
+ `/sign-in/phone-number` (better-auth phoneNumber plugin, framework#2780). It
12
+ coexists with the existing phone-OTP mode.
13
+
14
+ - Gated on `features.phoneNumber` (phoneNumber plugin enabled). Unlike phone-OTP
15
+ it needs no SMS service, so it uses that coarser capability flag, not
16
+ `features.phoneNumberOtp`. When the flag is off the field stays email-only.
17
+ - New `AuthClient.signInWithPhonePassword(phoneNumber, password)` wired through
18
+ `AuthContext` / `AuthProvider` / `useAuth`.
19
+ - New `normalizePhoneIdentifier` / `looksLikePhoneIdentifier` helpers that mirror
20
+ the backend's `normalizePhoneNumber` exactly (strip `[\s\-().]`, validate
21
+ `^\+?[0-9]{6,15}$`, **no** forced E.164 / country code — the backend stores the
22
+ light-stripped form, so anything heavier would break the lookup).
23
+ - SSO stays email-only (a phone-shaped identifier no longer attempts domain
24
+ routing).
25
+
26
+ Only works for accounts that have both a phone number and a password set;
27
+ phone-only accounts set a password on first OTP sign-in.
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies [86c69c3]
32
+ - Updated dependencies [6a74160]
33
+ - @object-ui/types@14.0.0
34
+
35
+ ## 13.2.0
36
+
37
+ ### Patch Changes
38
+
39
+ - 53c40c2: feat: identity import — the stock ImportWizard now drives sys_user bulk import (framework#2782)
40
+
41
+ The Users list gets an Import entry for platform admins (gated on
42
+ `features.admin` from `/api/v1/auth/config` plus workspace-admin), wired to
43
+ the dedicated `POST /api/v1/auth/admin/import-users` pipeline instead of the
44
+ generic data import (which would bypass better-auth hashing and produce
45
+ accounts that can never sign in).
46
+
47
+ - **plugin-grid**: two generic, backend-agnostic ImportWizard slots —
48
+ `extraOptionsContent` (host-injected options on the preview step) and
49
+ `renderResultExtra` (host-rendered content on the result step).
50
+ - **app-shell**: identity import dataSource adapter — splits files into the
51
+ endpoint's ≤500-row batches (idempotent upsert makes re-runs safe), injects
52
+ the selected password policy, renumbers per-batch results onto the whole
53
+ file, and enriches rows with their sign-in identity. Password policy panel
54
+ (`none` default / `invite` / `temporary`) and a one-shot temporary-password
55
+ reveal with CSV download (client memory only — nothing is persisted).
56
+ Async-job/undo surfaces are hidden for identity import by design.
57
+ - **auth**: `AuthPublicConfig.features.admin` typing.
58
+ - **i18n**: en/zh strings for the identity import panels.
59
+ - @object-ui/types@13.2.0
60
+
3
61
  ## 13.1.0
4
62
 
5
63
  ### Patch Changes
@@ -47,6 +47,16 @@ export interface AuthContextValue {
47
47
  sendVerificationEmail: (email: string, callbackURL?: string) => Promise<void>;
48
48
  /** Reset password with token */
49
49
  resetPassword: (token: string, newPassword: string) => Promise<void>;
50
+ /** framework#2780 — request a sign-in OTP SMS for the phone number. */
51
+ sendPhoneOtp: (phoneNumber: string) => Promise<void>;
52
+ /** framework#2780 — sign in by verifying a phone OTP. */
53
+ signInWithPhoneOtp: (phoneNumber: string, code: string) => Promise<void>;
54
+ /** framework#2780 — sign in with phone number + password (no SMS required). */
55
+ signInWithPhonePassword: (phoneNumber: string, password: string) => Promise<void>;
56
+ /** framework#2780 — request a password-reset OTP SMS for the phone number. */
57
+ requestPhonePasswordReset: (phoneNumber: string) => Promise<void>;
58
+ /** framework#2780 — reset the password with a phone OTP. */
59
+ resetPasswordWithPhoneOtp: (phoneNumber: string, otp: string, newPassword: string) => Promise<void>;
50
60
  /**
51
61
  * Change the local (email/password) password. Requires the current
52
62
  * password. Use this when `hasLocalPassword()` returns true.
@@ -1 +1 @@
1
- {"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../src/AuthContext.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../src/AuthContext.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../src/AuthProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAoD,MAAM,OAAO,CAAC;AAEzE,OAAO,KAAK,EAAwB,kBAAkB,EAAE,kBAAkB,EAAyG,MAAM,SAAS,CAAC;AAKnM,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,MAAM,EAAE,cAAc,EACtB,iBAAiB,EACjB,OAAc,EACd,WAAW,EACX,QAAQ,GACT,EAAE,iBAAiB,qBAqjBnB"}
1
+ {"version":3,"file":"AuthProvider.d.ts","sourceRoot":"","sources":["../src/AuthProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAoD,MAAM,OAAO,CAAC;AAEzE,OAAO,KAAK,EAAwB,kBAAkB,EAAE,kBAAkB,EAAyG,MAAM,SAAS,CAAC;AAKnM,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,MAAM,EAAE,cAAc,EACtB,iBAAiB,EACjB,OAAc,EACd,WAAW,EACX,QAAQ,GACT,EAAE,iBAAiB,qBA6oBnB"}
@@ -230,6 +230,74 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
230
230
  throw authError;
231
231
  }
232
232
  }, [client]);
233
+ // --- Phone-number OTP (framework#2780) --------------------------------
234
+ const sendPhoneOtp = useCallback(async (phoneNumber) => {
235
+ setError(null);
236
+ try {
237
+ await client.sendPhoneOtp(phoneNumber);
238
+ }
239
+ catch (err) {
240
+ const authError = err instanceof Error ? err : new Error(String(err));
241
+ setError(authError);
242
+ throw authError;
243
+ }
244
+ }, [client]);
245
+ const signInWithPhoneOtp = useCallback(async (phoneNumber, code) => {
246
+ setIsLoading(true);
247
+ setError(null);
248
+ try {
249
+ const result = await client.signInWithPhoneOtp(phoneNumber, code);
250
+ setUser(result.user);
251
+ setSession(result.session);
252
+ }
253
+ catch (err) {
254
+ const authError = err instanceof Error ? err : new Error(String(err));
255
+ setError(authError);
256
+ throw authError;
257
+ }
258
+ finally {
259
+ setIsLoading(false);
260
+ }
261
+ }, [client]);
262
+ const signInWithPhonePassword = useCallback(async (phoneNumber, password) => {
263
+ setIsLoading(true);
264
+ setError(null);
265
+ try {
266
+ const result = await client.signInWithPhonePassword(phoneNumber, password);
267
+ setUser(result.user);
268
+ setSession(result.session);
269
+ }
270
+ catch (err) {
271
+ const authError = err instanceof Error ? err : new Error(String(err));
272
+ setError(authError);
273
+ throw authError;
274
+ }
275
+ finally {
276
+ setIsLoading(false);
277
+ }
278
+ }, [client]);
279
+ const requestPhonePasswordReset = useCallback(async (phoneNumber) => {
280
+ setError(null);
281
+ try {
282
+ await client.requestPhonePasswordReset(phoneNumber);
283
+ }
284
+ catch (err) {
285
+ const authError = err instanceof Error ? err : new Error(String(err));
286
+ setError(authError);
287
+ throw authError;
288
+ }
289
+ }, [client]);
290
+ const resetPasswordWithPhoneOtp = useCallback(async (phoneNumber, otp, newPassword) => {
291
+ setError(null);
292
+ try {
293
+ await client.resetPasswordWithPhoneOtp(phoneNumber, otp, newPassword);
294
+ }
295
+ catch (err) {
296
+ const authError = err instanceof Error ? err : new Error(String(err));
297
+ setError(authError);
298
+ throw authError;
299
+ }
300
+ }, [client]);
233
301
  // ADR-0069 — the API fetch interceptor emits an auth-policy gate; raise the
234
302
  // remediation overlay. Don't override an already-shown gate.
235
303
  useEffect(() => {
@@ -457,6 +525,11 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
457
525
  forgotPassword,
458
526
  sendVerificationEmail,
459
527
  resetPassword,
528
+ sendPhoneOtp,
529
+ signInWithPhoneOtp,
530
+ signInWithPhonePassword,
531
+ requestPhonePasswordReset,
532
+ resetPasswordWithPhoneOtp,
460
533
  changePassword,
461
534
  remediationRequired,
462
535
  setRemediationRequired,
@@ -489,6 +562,7 @@ export function AuthProvider({ authUrl, client: externalClient, onAuthStateChang
489
562
  }), [
490
563
  user, session, isAuthenticated, isAuthEnabled, isLoading, error, isPreviewMode, previewMode,
491
564
  signIn, signUp, signOut, updateUser, forgotPassword, sendVerificationEmail, resetPassword, changePassword, setInitialPassword, hasLocalPassword, getAuthConfig, signInWithProvider,
565
+ sendPhoneOtp, signInWithPhoneOtp, signInWithPhonePassword, requestPhonePasswordReset, resetPasswordWithPhoneOtp,
492
566
  remediationRequired, enrollTotp, verifyTotp,
493
567
  organizations, activeOrganization, activeMember, isOrganizationsLoading, switchOrganization, createOrganization, refreshOrganizations,
494
568
  updateOrganization, deleteOrganization, leaveOrganization,
@@ -18,6 +18,32 @@ export interface ForgotPasswordFormLabels {
18
18
  backToSignInText?: string;
19
19
  rememberPasswordText?: string;
20
20
  signInText?: string;
21
+ /** Phone reset (framework#2780) — phone field label (defaults to "Phone number"). */
22
+ phoneLabel?: string;
23
+ /** Phone reset — phone field placeholder (defaults to "+1 555 000 0000"). */
24
+ phonePlaceholder?: string;
25
+ /** Phone reset — code field label (defaults to "Verification code"). */
26
+ otpCodeLabel?: string;
27
+ /** Phone reset — code field placeholder (defaults to "6-digit code"). */
28
+ otpCodePlaceholder?: string;
29
+ /** Phone reset — "send code" button (defaults to "Get code"). */
30
+ sendOtpButton?: string;
31
+ /** Phone reset — resend countdown, `{seconds}` hole (defaults to "Resend in {seconds}s"). */
32
+ resendOtpCountdownText?: string;
33
+ /** Phone reset — new password field label (defaults to "New password"). */
34
+ newPasswordLabel?: string;
35
+ /** Phone reset — new password placeholder (defaults to "Enter a new password"). */
36
+ newPasswordPlaceholder?: string;
37
+ /** Phone reset — submit button (defaults to "Reset Password"). */
38
+ resetButton?: string;
39
+ /** Link that switches to the phone (SMS code) branch (defaults to "Reset via SMS code"). */
40
+ usePhoneResetText?: string;
41
+ /** Link that switches back to the email branch (defaults to "Reset via email instead"). */
42
+ useEmailResetText?: string;
43
+ /** Phone reset — success screen title (defaults to "Password reset"). */
44
+ phoneSuccessTitle?: string;
45
+ /** Phone reset — success screen description. */
46
+ phoneSuccessDescription?: string;
21
47
  }
22
48
  export interface ForgotPasswordFormProps {
23
49
  /** Callback on successful submission */
@@ -1 +1 @@
1
- {"version":3,"file":"ForgotPasswordForm.d.ts","sourceRoot":"","sources":["../src/ForgotPasswordForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAYtD,qDAAqD;AACrD,MAAM,WAAW,wBAAwB;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,wBAAwB;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAqBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,OAAO,EACP,QAAmB,EACnB,KAA6B,EAC7B,WAAyF,EACzF,IAAI,EACJ,QAAgB,EAChB,aAAa,EAAE,QAAsB,EACrC,MAAW,GACZ,EAAE,uBAAuB,qBAyGzB"}
1
+ {"version":3,"file":"ForgotPasswordForm.d.ts","sourceRoot":"","sources":["../src/ForgotPasswordForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAYtD,qDAAqD;AACrD,MAAM,WAAW,wBAAwB;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6FAA6F;IAC7F,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mFAAmF;IACnF,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,2FAA2F;IAC3F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gDAAgD;IAChD,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,uBAAuB;IACtC,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,wBAAwB;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,yBAAyB;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAqBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,OAAO,EACP,QAAmB,EACnB,KAA6B,EAC7B,WAAyF,EACzF,IAAI,EACJ,QAAgB,EAChB,aAAa,EAAE,QAAsB,EACrC,MAAW,GACZ,EAAE,uBAAuB,qBAyUzB"}
@@ -6,7 +6,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
6
  * This source code is licensed under the MIT license found in the
7
7
  * LICENSE file in the root directory of this source tree.
8
8
  */
9
- import { useState } from 'react';
9
+ import { useEffect, useState } from 'react';
10
10
  import { useAuth } from './useAuth';
11
11
  import { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthErrorBanner, AuthFormHeader, AuthMailIcon, AuthSpinner, } from './authStyles';
12
12
  const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href, className: className, children: children }));
@@ -25,10 +25,46 @@ const DefaultKeyIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none",
25
25
  * ```
26
26
  */
27
27
  export function ForgotPasswordForm({ onSuccess, onError, loginUrl = '/login', title = 'Reset your password', description = "Enter your email address and we'll send you a link to reset your password", icon, hideIcon = false, linkComponent: LinkComp = DefaultLink, labels = {}, }) {
28
- const { forgotPassword, isLoading } = useAuth();
28
+ const { forgotPassword, isLoading, getAuthConfig, requestPhonePasswordReset, resetPasswordWithPhoneOtp, } = useAuth();
29
29
  const [email, setEmail] = useState('');
30
30
  const [error, setError] = useState(null);
31
31
  const [submitted, setSubmitted] = useState(false);
32
+ // Phone (SMS OTP) reset branch (framework#2780). Only offered when the
33
+ // server reports `features.phoneNumberOtp` — the phoneNumber plugin plus a
34
+ // deliverable SMS service — so the link never leads to codes that can't
35
+ // arrive.
36
+ const [phoneOtpEnabled, setPhoneOtpEnabled] = useState(false);
37
+ const [mode, setMode] = useState('email');
38
+ const [phone, setPhone] = useState('');
39
+ const [otpCode, setOtpCode] = useState('');
40
+ const [newPassword, setNewPassword] = useState('');
41
+ const [otpSending, setOtpSending] = useState(false);
42
+ const [otpSent, setOtpSent] = useState(false);
43
+ const [otpCooldown, setOtpCooldown] = useState(0);
44
+ const [phoneResetDone, setPhoneResetDone] = useState(false);
45
+ const [resetting, setResetting] = useState(false);
46
+ useEffect(() => {
47
+ let cancelled = false;
48
+ Promise.resolve()
49
+ .then(() => getAuthConfig())
50
+ .then((config) => {
51
+ if (!cancelled)
52
+ setPhoneOtpEnabled(config?.features?.phoneNumberOtp === true);
53
+ })
54
+ .catch(() => {
55
+ // Phone reset is an enhancement — a failed config fetch just hides it.
56
+ });
57
+ return () => {
58
+ cancelled = true;
59
+ };
60
+ }, [getAuthConfig]);
61
+ // Tick the resend cooldown down once per second while it's armed.
62
+ useEffect(() => {
63
+ if (otpCooldown <= 0)
64
+ return;
65
+ const timer = setTimeout(() => setOtpCooldown((s) => (s > 1 ? s - 1 : 0)), 1000);
66
+ return () => clearTimeout(timer);
67
+ }, [otpCooldown]);
32
68
  const l = {
33
69
  emailLabel: labels.emailLabel ?? 'Email',
34
70
  emailPlaceholder: labels.emailPlaceholder ?? 'name@example.com',
@@ -40,6 +76,20 @@ export function ForgotPasswordForm({ onSuccess, onError, loginUrl = '/login', ti
40
76
  backToSignInText: labels.backToSignInText ?? 'Back to sign in',
41
77
  rememberPasswordText: labels.rememberPasswordText ?? 'Remember your password?',
42
78
  signInText: labels.signInText ?? 'Sign in',
79
+ phoneLabel: labels.phoneLabel ?? 'Phone number',
80
+ phonePlaceholder: labels.phonePlaceholder ?? '+1 555 000 0000',
81
+ otpCodeLabel: labels.otpCodeLabel ?? 'Verification code',
82
+ otpCodePlaceholder: labels.otpCodePlaceholder ?? '6-digit code',
83
+ sendOtpButton: labels.sendOtpButton ?? 'Get code',
84
+ resendOtpCountdownText: labels.resendOtpCountdownText ?? 'Resend in {seconds}s',
85
+ newPasswordLabel: labels.newPasswordLabel ?? 'New password',
86
+ newPasswordPlaceholder: labels.newPasswordPlaceholder ?? 'Enter a new password',
87
+ resetButton: labels.resetButton ?? 'Reset Password',
88
+ usePhoneResetText: labels.usePhoneResetText ?? 'Reset via SMS code',
89
+ useEmailResetText: labels.useEmailResetText ?? 'Reset via email instead',
90
+ phoneSuccessTitle: labels.phoneSuccessTitle ?? 'Password reset',
91
+ phoneSuccessDescription: labels.phoneSuccessDescription ??
92
+ 'Your password has been reset. You can now sign in with your new password.',
43
93
  };
44
94
  const handleSubmit = async (e) => {
45
95
  e.preventDefault();
@@ -55,11 +105,62 @@ export function ForgotPasswordForm({ onSuccess, onError, loginUrl = '/login', ti
55
105
  onError?.(authError);
56
106
  }
57
107
  };
108
+ /**
109
+ * Request a reset OTP for the entered number (framework#2780). The server
110
+ * always answers success (no account-existence oracle); a 429 from the
111
+ * per-number cooldown surfaces its honest "retry in Ns" message.
112
+ */
113
+ const handleSendOtp = async () => {
114
+ if (!phone.trim() || otpSending || otpCooldown > 0)
115
+ return;
116
+ setError(null);
117
+ setOtpSending(true);
118
+ try {
119
+ await requestPhonePasswordReset(phone.trim());
120
+ setOtpSent(true);
121
+ setOtpCooldown(60);
122
+ }
123
+ catch (err) {
124
+ const authError = err instanceof Error ? err : new Error(String(err));
125
+ setError(authError.message);
126
+ onError?.(authError);
127
+ }
128
+ finally {
129
+ setOtpSending(false);
130
+ }
131
+ };
132
+ const handlePhoneReset = async (e) => {
133
+ e.preventDefault();
134
+ setError(null);
135
+ setResetting(true);
136
+ try {
137
+ await resetPasswordWithPhoneOtp(phone.trim(), otpCode.trim(), newPassword);
138
+ setPhoneResetDone(true);
139
+ onSuccess?.();
140
+ }
141
+ catch (err) {
142
+ const authError = err instanceof Error ? err : new Error(String(err));
143
+ setError(authError.message);
144
+ onError?.(authError);
145
+ }
146
+ finally {
147
+ setResetting(false);
148
+ }
149
+ };
150
+ const switchMode = (next) => {
151
+ setMode(next);
152
+ setError(null);
153
+ };
154
+ if (phoneResetDone) {
155
+ return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: _jsx("span", { className: "flex h-12 w-12 items-center justify-center rounded-2xl bg-emerald-500/10 text-emerald-600 ring-1 ring-emerald-500/15 dark:text-emerald-400", children: _jsx(AuthMailIcon, {}) }), title: l.phoneSuccessTitle, description: l.phoneSuccessDescription }), loginUrl && (_jsx("p", { className: "text-center text-sm text-muted-foreground", children: _jsxs(LinkComp, { href: loginUrl, className: AUTH_LINK_CLASS, children: ["\u2190 ", l.backToSignInText] }) }))] }));
156
+ }
58
157
  if (submitted) {
59
158
  const successMsg = l.successDescription.includes('{{email}}')
60
159
  ? l.successDescription.replace('{{email}}', email)
61
160
  : `${l.successDescription} ${email}`;
62
161
  return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: _jsx("span", { className: "flex h-12 w-12 items-center justify-center rounded-2xl bg-emerald-500/10 text-emerald-600 ring-1 ring-emerald-500/15 dark:text-emerald-400", children: _jsx(AuthMailIcon, {}) }), title: l.successTitle, description: successMsg }), loginUrl && (_jsx("p", { className: "text-center text-sm text-muted-foreground", children: _jsxs(LinkComp, { href: loginUrl, className: AUTH_LINK_CLASS, children: ["\u2190 ", l.backToSignInText] }) }))] }));
63
162
  }
64
- return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultKeyIcon, {})), title: title, description: description }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "forgot-email", className: AUTH_FIELD_LABEL_CLASS, children: l.emailLabel }), _jsx("input", { id: "forgot-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("button", { type: "submit", disabled: isLoading, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] })] }), loginUrl && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.rememberPasswordText, ' ', _jsx(LinkComp, { href: loginUrl, className: AUTH_LINK_CLASS, children: l.signInText })] }))] }));
163
+ return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultKeyIcon, {})), title: title, description: description }), mode === 'phone' ? (_jsxs("form", { onSubmit: handlePhoneReset, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "forgot-phone", className: AUTH_FIELD_LABEL_CLASS, children: l.phoneLabel }), _jsx("input", { id: "forgot-phone", type: "tel", placeholder: l.phonePlaceholder, value: phone, onChange: (e) => setPhone(e.target.value), required: true, autoComplete: "tel", disabled: resetting, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "forgot-otp", className: AUTH_FIELD_LABEL_CLASS, children: l.otpCodeLabel }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { id: "forgot-otp", type: "text", inputMode: "numeric", placeholder: l.otpCodePlaceholder, value: otpCode, onChange: (e) => setOtpCode(e.target.value), required: true, autoComplete: "one-time-code", disabled: resetting, className: AUTH_INPUT_CLASS }), _jsxs("button", { type: "button", onClick: handleSendOtp, disabled: otpSending || otpCooldown > 0 || !phone.trim() || resetting, className: "shrink-0 rounded-md border border-input bg-background px-3 py-2 text-sm font-medium transition-colors hover:bg-accent disabled:opacity-50", children: [otpSending && _jsx(AuthSpinner, {}), otpCooldown > 0
164
+ ? l.resendOtpCountdownText.replace('{seconds}', String(otpCooldown))
165
+ : l.sendOtpButton] })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "forgot-new-password", className: AUTH_FIELD_LABEL_CLASS, children: l.newPasswordLabel }), _jsx("input", { id: "forgot-new-password", type: "password", placeholder: l.newPasswordPlaceholder, value: newPassword, onChange: (e) => setNewPassword(e.target.value), required: true, autoComplete: "new-password", disabled: resetting, className: AUTH_INPUT_CLASS })] }), _jsxs("button", { type: "submit", disabled: resetting || !otpSent, className: AUTH_PRIMARY_BUTTON_CLASS, children: [resetting && _jsx(AuthSpinner, {}), resetting ? l.submittingButton : l.resetButton] }), _jsx("button", { type: "button", onClick: () => switchMode('email'), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.useEmailResetText })] })) : (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "forgot-email", className: AUTH_FIELD_LABEL_CLASS, children: l.emailLabel }), _jsx("input", { id: "forgot-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("button", { type: "submit", disabled: isLoading, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] }), phoneOtpEnabled && (_jsx("button", { type: "button", onClick: () => switchMode('phone'), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.usePhoneResetText }))] })), loginUrl && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.rememberPasswordText, ' ', _jsx(LinkComp, { href: loginUrl, className: AUTH_LINK_CLASS, children: l.signInText })] }))] }));
65
166
  }
@@ -11,6 +11,10 @@ import type { AuthLinkComponentProps } from './types';
11
11
  export interface LoginFormLabels {
12
12
  emailLabel?: string;
13
13
  emailPlaceholder?: string;
14
+ /** Identifier label when phone+password is enabled (defaults to "Email or phone number"). */
15
+ emailOrPhoneLabel?: string;
16
+ /** Identifier placeholder when phone+password is enabled. */
17
+ emailOrPhonePlaceholder?: string;
14
18
  passwordLabel?: string;
15
19
  passwordPlaceholder?: string;
16
20
  forgotPasswordText?: string;
@@ -30,6 +34,22 @@ export interface LoginFormLabels {
30
34
  usePasswordText?: string;
31
35
  /** Link to collapse the revealed break-glass form back to SSO-only (defaults to "Back to single sign-on"). */
32
36
  backToSsoText?: string;
37
+ /** Phone-OTP mode (framework#2780) — phone field label (defaults to "Phone number"). */
38
+ phoneLabel?: string;
39
+ /** Phone-OTP mode — phone field placeholder (defaults to "+1 555 000 0000"). */
40
+ phonePlaceholder?: string;
41
+ /** Phone-OTP mode — code field label (defaults to "Verification code"). */
42
+ otpCodeLabel?: string;
43
+ /** Phone-OTP mode — code field placeholder (defaults to "6-digit code"). */
44
+ otpCodePlaceholder?: string;
45
+ /** Phone-OTP mode — "send code" button (defaults to "Get code"). */
46
+ sendOtpButton?: string;
47
+ /** Phone-OTP mode — resend countdown, `{seconds}` hole (defaults to "Resend in {seconds}s"). */
48
+ resendOtpCountdownText?: string;
49
+ /** Link that switches to phone-OTP sign-in (defaults to "Sign in with verification code"). */
50
+ usePhoneOtpText?: string;
51
+ /** Link that switches back to password sign-in (defaults to "Sign in with password instead"). */
52
+ usePasswordSignInText?: string;
33
53
  /** Description shown above the form in SSO-only mode (defaults to "Sign in with your organization's single sign-on"). */
34
54
  ssoOnlyDescription?: string;
35
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../src/LoginForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAYtD,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8GAA8G;IAC9G,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yHAAyH;IACzH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,OAAO,EACP,WAAyB,EACzB,iBAAsC,EACtC,KAAiC,EACjC,WAAyD,EACzD,IAAI,EACJ,QAAgB,EAChB,aAAa,EAAE,QAAsB,EACrC,MAAW,EACX,aAAa,GACd,EAAE,cAAc,qBAmOhB"}
1
+ {"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../src/LoginForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAYtD,4CAA4C;AAC5C,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6FAA6F;IAC7F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6DAA6D;IAC7D,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8GAA8G;IAC9G,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,8FAA8F;IAC9F,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iGAAiG;IACjG,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,yHAAyH;IACzH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC5D,uCAAuC;IACvC,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAsBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,OAAO,EACP,WAAyB,EACzB,iBAAsC,EACtC,KAAiC,EACjC,WAAyD,EACzD,IAAI,EACJ,QAAgB,EAChB,aAAa,EAAE,QAAsB,EACrC,MAAW,EACX,aAAa,GACd,EAAE,cAAc,qBAsZhB"}
package/dist/LoginForm.js CHANGED
@@ -9,6 +9,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
9
  import { useEffect, useState } from 'react';
10
10
  import { useAuth } from './useAuth';
11
11
  import { SocialSignInButtons } from './SocialSignInButtons';
12
+ import { looksLikePhoneIdentifier, normalizePhoneIdentifier } from './phone-identifier';
12
13
  import { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthDivider, AuthErrorBanner, AuthFormHeader, AuthSpinner, } from './authStyles';
13
14
  const DefaultLink = ({ href, className, children }) => (_jsx("a", { href: href, className: className, children: children }));
14
15
  const DefaultLockIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round", className: "h-6 w-6", "aria-hidden": "true", children: [_jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2" }), _jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })] }));
@@ -27,10 +28,28 @@ const DefaultLockIcon = () => (_jsxs("svg", { viewBox: "0 0 24 24", fill: "none"
27
28
  * ```
28
29
  */
29
30
  export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgotPasswordUrl = '/forgot-password', title = 'Sign in to your account', description = 'Enter your email and password to continue', icon, hideIcon = false, linkComponent: LinkComp = DefaultLink, labels = {}, errorMessages, }) {
30
- const { signIn, isLoading, getAuthConfig } = useAuth();
31
+ const { signIn, isLoading, getAuthConfig, sendPhoneOtp, signInWithPhoneOtp, signInWithPhonePassword } = useAuth();
31
32
  const [email, setEmail] = useState('');
32
33
  const [password, setPassword] = useState('');
33
34
  const [error, setError] = useState(null);
35
+ // Phone-OTP sign-in (framework#2780). Only offered when the server reports
36
+ // `features.phoneNumberOtp` — i.e. the phoneNumber plugin is on AND a
37
+ // deliverable SMS service is wired — so the mode never renders as a dead
38
+ // entry point whose code can never arrive.
39
+ const [phoneOtpEnabled, setPhoneOtpEnabled] = useState(false);
40
+ // Phone + password sign-in (framework#2780). Offered when the server reports
41
+ // `features.phoneNumber` — the phoneNumber plugin is on. Unlike OTP this needs
42
+ // no SMS service, so it's gated on the coarser flag: the password-mode
43
+ // identifier field then accepts an email OR a phone number.
44
+ const [phonePasswordEnabled, setPhonePasswordEnabled] = useState(false);
45
+ const [mode, setMode] = useState('password');
46
+ const [phone, setPhone] = useState('');
47
+ const [otpCode, setOtpCode] = useState('');
48
+ const [otpSending, setOtpSending] = useState(false);
49
+ const [otpSent, setOtpSent] = useState(false);
50
+ // Seconds until another code may be requested — mirrors the server's
51
+ // per-number cooldown so the button doesn't invite guaranteed 429s.
52
+ const [otpCooldown, setOtpCooldown] = useState(0);
34
53
  const [hasSocialProviders, setHasSocialProviders] = useState(false);
35
54
  // Enterprise SSO is opt-in server-side (`@better-auth/sso`). Mirror the
36
55
  // social-provider pattern below: ask the server whether SSO is wired and
@@ -47,6 +66,10 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
47
66
  // Break-glass: reveal the password form for the env owner / local admin even
48
67
  // under enforced mode (e.g. during an IdP outage).
49
68
  const [showPasswordFallback, setShowPasswordFallback] = useState(false);
69
+ // In-flight `/sign-in/sso` round-trip — the button needs its own pending
70
+ // state because SSO routing is a raw fetch, not the shared `signIn` (whose
71
+ // `isLoading` drives the password submit button).
72
+ const [ssoSubmitting, setSsoSubmitting] = useState(false);
50
73
  useEffect(() => {
51
74
  let cancelled = false;
52
75
  Promise.resolve()
@@ -55,6 +78,8 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
55
78
  if (cancelled)
56
79
  return;
57
80
  setSsoEnabled(config?.features?.sso === true);
81
+ setPhoneOtpEnabled(config?.features?.phoneNumberOtp === true);
82
+ setPhonePasswordEnabled(config?.features?.phoneNumber === true);
58
83
  setSsoEnforced(config?.features?.ssoEnforced === true ||
59
84
  config?.emailPassword?.enabled === false);
60
85
  })
@@ -72,6 +97,8 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
72
97
  const l = {
73
98
  emailLabel: labels.emailLabel ?? 'Email',
74
99
  emailPlaceholder: labels.emailPlaceholder ?? 'name@example.com',
100
+ emailOrPhoneLabel: labels.emailOrPhoneLabel ?? 'Email or phone number',
101
+ emailOrPhonePlaceholder: labels.emailOrPhonePlaceholder ?? 'name@example.com or +1 555 000 0000',
75
102
  passwordLabel: labels.passwordLabel ?? 'Password',
76
103
  passwordPlaceholder: labels.passwordPlaceholder ?? 'Enter your password',
77
104
  forgotPasswordText: labels.forgotPasswordText ?? 'Forgot password?',
@@ -84,12 +111,38 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
84
111
  usePasswordText: labels.usePasswordText ?? 'Use a password instead',
85
112
  backToSsoText: labels.backToSsoText ?? 'Back to single sign-on',
86
113
  ssoOnlyDescription: labels.ssoOnlyDescription ?? "Sign in with your organization's single sign-on",
114
+ phoneLabel: labels.phoneLabel ?? 'Phone number',
115
+ phonePlaceholder: labels.phonePlaceholder ?? '+1 555 000 0000',
116
+ otpCodeLabel: labels.otpCodeLabel ?? 'Verification code',
117
+ otpCodePlaceholder: labels.otpCodePlaceholder ?? '6-digit code',
118
+ sendOtpButton: labels.sendOtpButton ?? 'Get code',
119
+ resendOtpCountdownText: labels.resendOtpCountdownText ?? 'Resend in {seconds}s',
120
+ usePhoneOtpText: labels.usePhoneOtpText ?? 'Sign in with verification code',
121
+ usePasswordSignInText: labels.usePasswordSignInText ?? 'Sign in with password instead',
87
122
  };
123
+ // Tick the resend cooldown down once per second while it's armed.
124
+ useEffect(() => {
125
+ if (otpCooldown <= 0)
126
+ return;
127
+ const timer = setTimeout(() => setOtpCooldown((s) => (s > 1 ? s - 1 : 0)), 1000);
128
+ return () => clearTimeout(timer);
129
+ }, [otpCooldown]);
88
130
  const handleSubmit = async (e) => {
89
131
  e.preventDefault();
90
132
  setError(null);
91
133
  try {
92
- await signIn(email, password);
134
+ if (mode === 'phone-otp') {
135
+ await signInWithPhoneOtp(phone.trim(), otpCode.trim());
136
+ }
137
+ else if (phonePasswordEnabled && looksLikePhoneIdentifier(email)) {
138
+ // Unified identifier: a phone-shaped entry routes to phone+password.
139
+ // Normalize identically to the backend (strip formatting, no country
140
+ // code) or the phoneNumber lookup fails.
141
+ await signInWithPhonePassword(normalizePhoneIdentifier(email) ?? email.trim(), password);
142
+ }
143
+ else {
144
+ await signIn(email, password);
145
+ }
93
146
  onSuccess?.();
94
147
  }
95
148
  catch (err) {
@@ -99,6 +152,35 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
99
152
  onError?.(authError);
100
153
  }
101
154
  };
155
+ /**
156
+ * Request a sign-in OTP for the entered number. A 429 (per-number cooldown
157
+ * / hourly cap, framework#2780) surfaces the server's honest "retry in Ns"
158
+ * message; any other failure surfaces as-is.
159
+ */
160
+ const handleSendOtp = async () => {
161
+ if (!phone.trim() || otpSending || otpCooldown > 0)
162
+ return;
163
+ setError(null);
164
+ setOtpSending(true);
165
+ try {
166
+ await sendPhoneOtp(phone.trim());
167
+ setOtpSent(true);
168
+ setOtpCooldown(60);
169
+ }
170
+ catch (err) {
171
+ const authError = err instanceof Error ? err : new Error(String(err));
172
+ const code = authError.code;
173
+ setError((code && errorMessages?.[code]) || authError.message);
174
+ onError?.(authError);
175
+ }
176
+ finally {
177
+ setOtpSending(false);
178
+ }
179
+ };
180
+ const switchMode = (next) => {
181
+ setMode(next);
182
+ setError(null);
183
+ };
102
184
  /**
103
185
  * Federated SSO sign-in: routes the entered email to its configured IdP
104
186
  * (better-auth `@better-auth/sso`, by email domain) and redirects the
@@ -106,7 +188,15 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
106
188
  * error when no provider matches the domain.
107
189
  */
108
190
  const handleSso = async () => {
191
+ if (ssoSubmitting)
192
+ return;
109
193
  setError(null);
194
+ // SSO routes by email domain — a phone-shaped identifier can't map to an IdP.
195
+ if (looksLikePhoneIdentifier(email)) {
196
+ setError('Enter your email address to sign in with SSO.');
197
+ return;
198
+ }
199
+ setSsoSubmitting(true);
110
200
  try {
111
201
  const base = window.location.pathname.replace(/\/login(?:\/.*)?$/, '');
112
202
  const res = await fetch('/api/v1/auth/sign-in/sso', {
@@ -117,14 +207,22 @@ export function LoginForm({ onSuccess, onError, registerUrl = '/register', forgo
117
207
  });
118
208
  const data = (await res.json().catch(() => ({})));
119
209
  if (res.ok && typeof data.url === 'string') {
210
+ // Navigating to the IdP — keep the pending state through teardown.
120
211
  window.location.href = data.url;
121
212
  return;
122
213
  }
123
214
  setError(data.message || 'No SSO provider is configured for this email domain.');
215
+ setSsoSubmitting(false);
124
216
  }
125
217
  catch (err) {
126
218
  setError(err instanceof Error ? err.message : String(err));
219
+ setSsoSubmitting(false);
127
220
  }
128
221
  };
129
- return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultLockIcon, {})), title: title, description: ssoEnforced && !showPasswordFallback ? l.ssoOnlyDescription : description }), _jsxs("div", { className: "space-y-5", children: [_jsx(SocialSignInButtons, { mode: "sign-in", onProvidersResolved: (hasProviders) => setHasSocialProviders(hasProviders) }), passwordFormVisible ? (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [hasSocialProviders && _jsx(AuthDivider, { label: l.orText }), error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-email", className: AUTH_FIELD_LABEL_CLASS, children: l.emailLabel }), _jsx("input", { id: "login-email", type: "email", placeholder: l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "email", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { htmlFor: "login-password", className: AUTH_FIELD_LABEL_CLASS, children: l.passwordLabel }), forgotPasswordUrl && (_jsx(LinkComp, { href: forgotPasswordUrl, className: "text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.forgotPasswordText }))] }), _jsx("input", { id: "login-password", type: "password", placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "current-password", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("button", { type: "submit", disabled: isLoading, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] }), ssoEnabled && (_jsx("button", { type: "button", onClick: handleSso, disabled: isLoading, className: "flex w-full items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent disabled:opacity-50", children: l.ssoButton })), ssoEnforced && showPasswordFallback && (_jsx("button", { type: "button", onClick: () => setShowPasswordFallback(false), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.backToSsoText }))] })) : (_jsxs("div", { className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsx("button", { type: "button", onClick: () => setShowPasswordFallback(true), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.usePasswordText })] }))] }), registerUrl && !ssoEnforced && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.noAccountText, ' ', _jsx(LinkComp, { href: registerUrl, className: AUTH_LINK_CLASS, children: l.signUpText })] }))] }));
222
+ return (_jsxs("div", { className: "mx-auto flex w-full flex-col justify-center space-y-7 sm:w-[400px]", children: [_jsx(AuthFormHeader, { icon: hideIcon ? undefined : (icon ?? _jsx(DefaultLockIcon, {})), title: title, description: ssoEnforced && !showPasswordFallback ? l.ssoOnlyDescription : description }), _jsxs("div", { className: "space-y-5", children: [_jsx(SocialSignInButtons, { mode: "sign-in", onProvidersResolved: (hasProviders) => setHasSocialProviders(hasProviders) }), passwordFormVisible ? (mode === 'phone-otp' ? (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [hasSocialProviders && _jsx(AuthDivider, { label: l.orText }), error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-phone", className: AUTH_FIELD_LABEL_CLASS, children: l.phoneLabel }), _jsx("input", { id: "login-phone", type: "tel", placeholder: l.phonePlaceholder, value: phone, onChange: (e) => setPhone(e.target.value), required: true, autoComplete: "tel", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-otp", className: AUTH_FIELD_LABEL_CLASS, children: l.otpCodeLabel }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { id: "login-otp", type: "text", inputMode: "numeric", placeholder: l.otpCodePlaceholder, value: otpCode, onChange: (e) => setOtpCode(e.target.value), required: true, autoComplete: "one-time-code", disabled: isLoading, className: AUTH_INPUT_CLASS }), _jsxs("button", { type: "button", onClick: handleSendOtp, disabled: otpSending || otpCooldown > 0 || !phone.trim() || isLoading, className: "shrink-0 rounded-md border border-input bg-background px-3 py-2 text-sm font-medium transition-colors hover:bg-accent disabled:opacity-50", children: [otpSending && _jsx(AuthSpinner, {}), otpCooldown > 0
223
+ ? l.resendOtpCountdownText.replace('{seconds}', String(otpCooldown))
224
+ : l.sendOtpButton] })] })] }), _jsxs("button", { type: "submit", disabled: isLoading || !otpSent, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] }), _jsx("button", { type: "button", onClick: () => switchMode('password'), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.usePasswordSignInText })] })) : (_jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [hasSocialProviders && _jsx(AuthDivider, { label: l.orText }), error && _jsx(AuthErrorBanner, { message: error }), _jsxs("div", { className: "space-y-2", children: [_jsx("label", { htmlFor: "login-email", className: AUTH_FIELD_LABEL_CLASS, children: phonePasswordEnabled ? l.emailOrPhoneLabel : l.emailLabel }), _jsx("input", { id: "login-email",
225
+ // `text` (not `email`) when a phone number is also accepted, so the
226
+ // browser doesn't reject a phone-shaped value on native validation.
227
+ type: phonePasswordEnabled ? 'text' : 'email', inputMode: phonePasswordEnabled ? 'text' : 'email', placeholder: phonePasswordEnabled ? l.emailOrPhonePlaceholder : l.emailPlaceholder, value: email, onChange: (e) => setEmail(e.target.value), required: true, autoComplete: "username", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("label", { htmlFor: "login-password", className: AUTH_FIELD_LABEL_CLASS, children: l.passwordLabel }), forgotPasswordUrl && (_jsx(LinkComp, { href: forgotPasswordUrl, className: "text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.forgotPasswordText }))] }), _jsx("input", { id: "login-password", type: "password", placeholder: l.passwordPlaceholder, value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "current-password", disabled: isLoading, className: AUTH_INPUT_CLASS })] }), _jsxs("button", { type: "submit", disabled: isLoading, className: AUTH_PRIMARY_BUTTON_CLASS, children: [isLoading && _jsx(AuthSpinner, {}), isLoading ? l.submittingButton : l.submitButton] }), ssoEnabled && (_jsxs("button", { type: "button", onClick: handleSso, disabled: isLoading || ssoSubmitting, "aria-busy": ssoSubmitting, className: "flex w-full items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent disabled:opacity-50", children: [ssoSubmitting && _jsx(AuthSpinner, {}), l.ssoButton] })), phoneOtpEnabled && (_jsx("button", { type: "button", onClick: () => switchMode('phone-otp'), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.usePhoneOtpText })), ssoEnforced && showPasswordFallback && (_jsx("button", { type: "button", onClick: () => setShowPasswordFallback(false), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.backToSsoText }))] }))) : (_jsxs("div", { className: "space-y-4", children: [error && _jsx(AuthErrorBanner, { message: error }), _jsx("button", { type: "button", onClick: () => setShowPasswordFallback(true), className: "w-full text-center text-xs text-muted-foreground underline-offset-4 transition-colors hover:text-primary hover:underline", children: l.usePasswordText })] }))] }), registerUrl && !ssoEnforced && (_jsxs("p", { className: "px-8 text-center text-sm text-muted-foreground", children: [l.noAccountText, ' ', _jsx(LinkComp, { href: registerUrl, className: AUTH_LINK_CLASS, children: l.signUpText })] }))] }));
130
228
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SocialSignInButtons.d.ts","sourceRoot":"","sources":["../src/SocialSignInButtons.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAiFnD,MAAM,WAAW,wBAAwB;IACvC,sFAAsF;IACtF,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yFAAyF;IACzF,mBAAmB,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;CACvD;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,IAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,WAAsC,EACtC,mBAAmB,GACpB,EAAE,wBAAwB,4BA8E1B"}
1
+ {"version":3,"file":"SocialSignInButtons.d.ts","sourceRoot":"","sources":["../src/SocialSignInButtons.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA8B,MAAM,OAAO,CAAC;AAkFnD,MAAM,WAAW,wBAAwB;IACvC,sFAAsF;IACtF,IAAI,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC7B,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yFAAyF;IACzF,mBAAmB,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;CACvD;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,IAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,WAAsC,EACtC,mBAAmB,GACpB,EAAE,wBAAwB,4BAyF1B"}
@@ -8,6 +8,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  */
9
9
  import { useEffect, useState } from 'react';
10
10
  import { useAuth } from './useAuth';
11
+ import { AuthSpinner } from './authStyles';
11
12
  // Brand name overrides for providers whose `name` from the server may be unset
12
13
  // or where we want to canonicalize casing.
13
14
  const PROVIDER_LABEL = {
@@ -52,6 +53,10 @@ export function SocialSignInButtons({ mode = 'sign-in', callbackURL, errorCallba
52
53
  const [providers, setProviders] = useState([]);
53
54
  const [loading, setLoading] = useState(true);
54
55
  const [error, setError] = useState(null);
56
+ // Provider id of the in-flight `signInWithProvider` call. Sign-in ends in a
57
+ // full-page navigation, so the spinner deliberately stays on until unload —
58
+ // it is only cleared when the call FAILS and the user needs the button back.
59
+ const [pendingId, setPendingId] = useState(null);
55
60
  useEffect(() => {
56
61
  let cancelled = false;
57
62
  // Wrap in Promise.resolve so synchronous throws (e.g. mock client without
@@ -84,17 +89,23 @@ export function SocialSignInButtons({ mode = 'sign-in', callbackURL, errorCallba
84
89
  const label = mode === 'sign-in' ? 'Continue with' : 'Sign up with';
85
90
  const defaultCallback = typeof window !== 'undefined' ? window.location.href : undefined;
86
91
  const onClick = async (provider) => {
92
+ if (pendingId)
93
+ return;
87
94
  setError(null);
95
+ setPendingId(provider.id);
88
96
  try {
89
97
  await signInWithProvider(provider.id, {
90
98
  callbackURL: callbackURL ?? defaultCallback,
91
99
  errorCallbackURL: errorCallbackURL ?? callbackURL ?? defaultCallback,
92
100
  type: provider.type ?? 'social',
93
101
  });
102
+ // Success = the browser is navigating to the provider. Keep the pending
103
+ // state so the button doesn't "un-busy" during the page teardown.
94
104
  }
95
105
  catch (err) {
96
106
  setError(err instanceof Error ? err.message : String(err));
107
+ setPendingId(null);
97
108
  }
98
109
  };
99
- return (_jsxs("div", { className: "flex flex-col gap-2", children: [error && (_jsx("div", { className: "rounded-md bg-destructive/15 p-3 text-sm text-destructive", role: "alert", children: error })), providers.map((p) => (_jsxs("button", { type: "button", onClick: () => onClick(p), className: "inline-flex h-10 w-full items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", children: [_jsx(ProviderIcon, { id: p.id }), label, " ", PROVIDER_LABEL[p.id] ?? p.name] }, p.id))), _jsxs("div", { className: "relative my-1", children: [_jsx("div", { className: "absolute inset-0 flex items-center", children: _jsx("span", { className: "w-full border-t" }) }), _jsx("div", { className: "relative flex justify-center text-xs uppercase", children: _jsx("span", { className: "bg-background px-2 text-muted-foreground", children: dividerText }) })] })] }));
110
+ return (_jsxs("div", { className: "flex flex-col gap-2", children: [error && (_jsx("div", { className: "rounded-md bg-destructive/15 p-3 text-sm text-destructive", role: "alert", children: error })), providers.map((p) => (_jsxs("button", { type: "button", onClick: () => onClick(p), disabled: pendingId !== null, "aria-busy": pendingId === p.id, className: "inline-flex h-10 w-full items-center justify-center rounded-md border border-input bg-background px-4 py-2 text-sm font-medium ring-offset-background transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", children: [pendingId === p.id ? _jsx(AuthSpinner, {}) : _jsx(ProviderIcon, { id: p.id }), label, " ", PROVIDER_LABEL[p.id] ?? p.name] }, p.id))), _jsxs("div", { className: "relative my-1", children: [_jsx("div", { className: "absolute inset-0 flex items-center", children: _jsx("span", { className: "w-full border-t" }) }), _jsx("div", { className: "relative flex justify-center text-xs uppercase", children: _jsx("span", { className: "bg-background px-2 text-muted-foreground", children: dividerText }) })] })] }));
100
111
  }
@@ -1 +1 @@
1
- {"version":3,"file":"createAuthClient.d.ts","sourceRoot":"","sources":["../src/createAuthClient.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,UAAU,EAAE,gBAAgB,EAE7B,MAAM,SAAS,CAAC;AAIjB;;;GAGG;AACH,eAAO,MAAM,YAAY;kBACD,MAAM,GAAG,IAAI;WAE5B,MAAM,GAAG,IAAI;eAST,MAAM,GAAG,IAAI;aASf,IAAI;CAQd,CAAC;AAmHF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CA0erE"}
1
+ {"version":3,"file":"createAuthClient.d.ts","sourceRoot":"","sources":["../src/createAuthClient.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,UAAU,EAAE,gBAAgB,EAE7B,MAAM,SAAS,CAAC;AAIjB;;;GAGG;AACH,eAAO,MAAM,YAAY;kBACD,MAAM,GAAG,IAAI;WAE5B,MAAM,GAAG,IAAI;eAST,MAAM,GAAG,IAAI;aASf,IAAI;CAQd,CAAC;AAmHF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAkkBrE"}
@@ -173,6 +173,29 @@ export function createAuthClient(config) {
173
173
  // than the runtime JSON the server actually sends (e.g. `session` on signIn).
174
174
  // We deliberately cast through `unknown` to bridge from better-auth types
175
175
  // to the ObjectUI AuthClient contract.
176
+ /**
177
+ * POST one of the phoneNumber plugin's endpoints (framework#2780) and
178
+ * return the parsed JSON. Throws an Error carrying the better-auth `code`
179
+ * and HTTP `status` so the forms can special-case the per-number cooldown
180
+ * (429 TOO_MANY_REQUESTS) with an honest "retry in Ns" message.
181
+ */
182
+ async function postPhoneNumberEndpoint(path, body) {
183
+ const response = await bearerFetch(`${origin}${basePath}${path}`, {
184
+ method: 'POST',
185
+ headers: { 'Content-Type': 'application/json' },
186
+ credentials: 'include',
187
+ body: JSON.stringify(body),
188
+ });
189
+ const payload = (await response.json().catch(() => ({})));
190
+ if (!response.ok) {
191
+ const err = new Error(payload?.message ?? `Auth request failed with status ${response.status}`);
192
+ if (payload?.code)
193
+ err.code = payload.code;
194
+ err.status = response.status;
195
+ throw err;
196
+ }
197
+ return payload ?? {};
198
+ }
176
199
  return {
177
200
  async signIn(credentials) {
178
201
  const { data, error } = await betterAuth.signIn.email({
@@ -313,6 +336,49 @@ export function createAuthClient(config) {
313
336
  throw new Error(error.message ?? `Auth request failed with status ${error.status}`);
314
337
  }
315
338
  },
339
+ // --- Phone-number OTP (framework#2780) -------------------------------
340
+ // The better-auth phoneNumber plugin's endpoints, called directly (the
341
+ // phoneNumberClient plugin adds nothing we need beyond these four POSTs,
342
+ // and direct fetch keeps the error `code`/status handy for the cooldown
343
+ // 429 UX). Server availability is gated by `features.phoneNumberOtp`.
344
+ async sendPhoneOtp(phoneNumber) {
345
+ await postPhoneNumberEndpoint('/phone-number/send-otp', { phoneNumber });
346
+ },
347
+ async signInWithPhoneOtp(phoneNumber, code) {
348
+ const payload = await postPhoneNumberEndpoint('/phone-number/verify', { phoneNumber, code });
349
+ // Response: `{ status, token: string|null, user: object|null }` —
350
+ // token/user are null when the number belongs to no account (the
351
+ // endpoint also serves the change-phone verification flow).
352
+ const token = typeof payload.token === 'string' ? payload.token : undefined;
353
+ const user = (payload.user ?? null);
354
+ if (!token || !user) {
355
+ throw new Error('No account is registered for this phone number.');
356
+ }
357
+ TokenStorage.set(token);
358
+ return { user, session: { token } };
359
+ },
360
+ async signInWithPhonePassword(phoneNumber, password) {
361
+ // Phone + password sign-in (better-auth `/sign-in/phone-number`). Needs
362
+ // no SMS service — gated server-side by `features.phoneNumber` (plugin
363
+ // on), NOT `features.phoneNumberOtp`. Response: `{ token, user }`, mirror
364
+ // of signInWithPhoneOtp.
365
+ const payload = await postPhoneNumberEndpoint('/sign-in/phone-number', { phoneNumber, password });
366
+ const token = typeof payload.token === 'string' ? payload.token : undefined;
367
+ const user = (payload.user ?? null);
368
+ if (!token || !user) {
369
+ throw new Error('Invalid phone number or password.');
370
+ }
371
+ TokenStorage.set(token);
372
+ return { user, session: { token } };
373
+ },
374
+ async requestPhonePasswordReset(phoneNumber) {
375
+ // Always answers `{status:true}` (no account-existence oracle) — the
376
+ // OTP only arrives when the number belongs to an account.
377
+ await postPhoneNumberEndpoint('/phone-number/request-password-reset', { phoneNumber });
378
+ },
379
+ async resetPasswordWithPhoneOtp(phoneNumber, otp, newPassword) {
380
+ await postPhoneNumberEndpoint('/phone-number/reset-password', { phoneNumber, otp, newPassword });
381
+ },
316
382
  async changePassword(currentPassword, newPassword, options) {
317
383
  const fn = betterAuth.changePassword;
318
384
  if (typeof fn !== 'function') {
@@ -436,7 +502,12 @@ export function createAuthClient(config) {
436
502
  if (error) {
437
503
  throw new Error(error.message ?? `Auth request failed with status ${error.status}`);
438
504
  }
439
- if (data?.url && typeof window !== 'undefined') {
505
+ // A missing redirect URL means the flow CANNOT continue — surface it
506
+ // instead of resolving silently (the user would see a dead button).
507
+ if (!data?.url) {
508
+ throw new Error(`Sign-in with "${providerId}" did not return a redirect URL — please try again or contact your administrator.`);
509
+ }
510
+ if (typeof window !== 'undefined') {
440
511
  window.location.href = data.url;
441
512
  }
442
513
  return;
@@ -450,7 +521,10 @@ export function createAuthClient(config) {
450
521
  throw new Error(error.message ?? `Auth request failed with status ${error.status}`);
451
522
  }
452
523
  const socialUrl = data?.url;
453
- if (socialUrl && typeof window !== 'undefined') {
524
+ if (!socialUrl) {
525
+ throw new Error(`Sign-in with "${providerId}" did not return a redirect URL — please try again or contact your administrator.`);
526
+ }
527
+ if (typeof window !== 'undefined') {
454
528
  window.location.href = socialUrl;
455
529
  }
456
530
  },
package/dist/index.d.ts CHANGED
@@ -31,6 +31,7 @@ export { SocialSignInButtons, type SocialSignInButtonsProps } from './SocialSign
31
31
  export { UserMenu, type UserMenuProps } from './UserMenu';
32
32
  export { PreviewBanner, type PreviewBannerProps } from './PreviewBanner';
33
33
  export { createAuthClient, TokenStorage } from './createAuthClient';
34
+ export { normalizePhoneIdentifier, looksLikePhoneIdentifier } from './phone-identifier';
34
35
  export { createAuthenticatedFetch, ActiveOrganizationStorage, type AuthenticatedAdapterOptions } from './createAuthenticatedFetch';
35
36
  export { getUserInitials } from './types';
36
37
  export { AUTH_FIELD_LABEL_CLASS, AUTH_INPUT_CLASS, AUTH_LINK_CLASS, AUTH_PRIMARY_BUTTON_CLASS, AuthAlertIcon, AuthCheckIcon, AuthDivider, AuthErrorBanner, AuthFormHeader, AuthMailIcon, AuthSpinner, } from './authStyles';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACvH,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,KAAK,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACnI,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI1C,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,yBAAyB,EACzB,aAAa,EACb,aAAa,EACb,WAAW,EACX,eAAe,EACf,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,cAAc,CAAC;AAGtB,YAAY,EACV,QAAQ,EACR,WAAW,EACX,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACvH,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,KAAK,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACnI,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI1C,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EACf,yBAAyB,EACzB,aAAa,EACb,aAAa,EACb,WAAW,EACX,eAAe,EACf,cAAc,EACd,YAAY,EACZ,WAAW,GACZ,MAAM,cAAc,CAAC;AAGtB,YAAY,EACV,QAAQ,EACR,WAAW,EACX,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ export { SocialSignInButtons } from './SocialSignInButtons';
31
31
  export { UserMenu } from './UserMenu';
32
32
  export { PreviewBanner } from './PreviewBanner';
33
33
  export { createAuthClient, TokenStorage } from './createAuthClient';
34
+ export { normalizePhoneIdentifier, looksLikePhoneIdentifier } from './phone-identifier';
34
35
  export { createAuthenticatedFetch, ActiveOrganizationStorage } from './createAuthenticatedFetch';
35
36
  export { getUserInitials } from './types';
36
37
  // Shared auth form primitives — exposed so consumers can build custom forms
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Identifier helpers shared by the login surfaces for phone sign-in
3
+ * (framework#2780).
4
+ *
5
+ * These MIRROR the backend's `normalizePhoneNumber`
6
+ * (`@objectstack/plugin-auth`): strip spaces / dashes / parens / dots, then
7
+ * validate `^\+?[0-9]{6,15}$`. They deliberately do NOT force E.164 or inject a
8
+ * country code — accounts are stored in exactly this light-stripped form, so
9
+ * anything heavier would fail the `phoneNumber` lookup at sign-in. Keep this in
10
+ * lock-step with the backend regex.
11
+ */
12
+ /** Strip formatting and validate; returns the canonical string or `null`. */
13
+ export declare function normalizePhoneIdentifier(raw: string): string | null;
14
+ /**
15
+ * Whether an identifier should be treated as a phone number rather than an
16
+ * email. An `@` always means email; otherwise it is a phone only when it
17
+ * normalizes to a valid number.
18
+ */
19
+ export declare function looksLikePhoneIdentifier(raw: string): boolean;
20
+ //# sourceMappingURL=phone-identifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phone-identifier.d.ts","sourceRoot":"","sources":["../src/phone-identifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,6EAA6E;AAC7E,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGnE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAG7D"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Identifier helpers shared by the login surfaces for phone sign-in
3
+ * (framework#2780).
4
+ *
5
+ * These MIRROR the backend's `normalizePhoneNumber`
6
+ * (`@objectstack/plugin-auth`): strip spaces / dashes / parens / dots, then
7
+ * validate `^\+?[0-9]{6,15}$`. They deliberately do NOT force E.164 or inject a
8
+ * country code — accounts are stored in exactly this light-stripped form, so
9
+ * anything heavier would fail the `phoneNumber` lookup at sign-in. Keep this in
10
+ * lock-step with the backend regex.
11
+ */
12
+ /** Strip formatting and validate; returns the canonical string or `null`. */
13
+ export function normalizePhoneIdentifier(raw) {
14
+ const stripped = String(raw ?? '').replace(/[\s\-().]/g, '');
15
+ return /^\+?[0-9]{6,15}$/.test(stripped) ? stripped : null;
16
+ }
17
+ /**
18
+ * Whether an identifier should be treated as a phone number rather than an
19
+ * email. An `@` always means email; otherwise it is a phone only when it
20
+ * normalizes to a valid number.
21
+ */
22
+ export function looksLikePhoneIdentifier(raw) {
23
+ if (typeof raw !== 'string' || raw.includes('@'))
24
+ return false;
25
+ return normalizePhoneIdentifier(raw) !== null;
26
+ }
package/dist/types.d.ts CHANGED
@@ -121,6 +121,26 @@ export interface AuthPublicConfig {
121
121
  * invite-accept) still work — only fresh creation is forbidden.
122
122
  */
123
123
  multiOrgEnabled?: boolean;
124
+ /**
125
+ * Phone-number sign-in enabled server-side (better-auth phoneNumber
126
+ * plugin — phone + password, framework#2766).
127
+ */
128
+ phoneNumber?: boolean;
129
+ /**
130
+ * Phone-number OTP sign-in / self-service reset available — requires the
131
+ * phoneNumber plugin plus a deliverable SMS service (framework#2780).
132
+ * Gates the "sign in with verification code" mode and the phone branch
133
+ * of the forgot-password form; falsy hides them so we never render an
134
+ * entry point whose code can never arrive.
135
+ */
136
+ phoneNumberOtp?: boolean;
137
+ /**
138
+ * better-auth admin plugin mounted server-side (`auth.plugins.admin`;
139
+ * SCIM forces it on). Gates the admin user-management surfaces — the
140
+ * sys_user create/set-password actions and the identity import wizard
141
+ * entry (framework#2766 / #2782).
142
+ */
143
+ admin?: boolean;
124
144
  };
125
145
  }
126
146
  /** Options when initiating a third-party sign-in */
@@ -158,6 +178,22 @@ export interface AuthClient {
158
178
  sendVerificationEmail: (email: string, callbackURL?: string) => Promise<void>;
159
179
  /** Reset password with token */
160
180
  resetPassword: (token: string, newPassword: string) => Promise<void>;
181
+ /** framework#2780 — request a sign-in/verification OTP SMS for the phone number. */
182
+ sendPhoneOtp: (phoneNumber: string) => Promise<void>;
183
+ /** framework#2780 — verify a phone OTP; signs in the number's user. */
184
+ signInWithPhoneOtp: (phoneNumber: string, code: string) => Promise<{
185
+ user: AuthUser;
186
+ session: AuthSession;
187
+ }>;
188
+ /** framework#2780 — sign in with phone number + password (no SMS; gated by `features.phoneNumber`). */
189
+ signInWithPhonePassword: (phoneNumber: string, password: string) => Promise<{
190
+ user: AuthUser;
191
+ session: AuthSession;
192
+ }>;
193
+ /** framework#2780 — request a password-reset OTP SMS for the phone number. */
194
+ requestPhonePasswordReset: (phoneNumber: string) => Promise<void>;
195
+ /** framework#2780 — reset the password using a phone OTP. */
196
+ resetPasswordWithPhoneOtp: (phoneNumber: string, otp: string, newPassword: string) => Promise<void>;
161
197
  /** Change password (requires current password). For users who already have a local password. */
162
198
  changePassword: (currentPassword: string, newPassword: string, options?: {
163
199
  revokeOtherSessions?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../src/useAuth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAW,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE/D;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,IAAI,gBAAgB,CAsD1C"}
1
+ {"version":3,"file":"useAuth.d.ts","sourceRoot":"","sources":["../src/useAuth.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAW,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE/D;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,IAAI,gBAAgB,CA2D1C"}
package/dist/useAuth.js CHANGED
@@ -40,6 +40,11 @@ export function useAuth() {
40
40
  forgotPassword: async () => { throw new Error('useAuth must be used within an AuthProvider'); },
41
41
  sendVerificationEmail: async () => { throw new Error('useAuth must be used within an AuthProvider'); },
42
42
  resetPassword: async () => { throw new Error('useAuth must be used within an AuthProvider'); },
43
+ sendPhoneOtp: async () => { throw new Error('useAuth must be used within an AuthProvider'); },
44
+ signInWithPhoneOtp: async () => { throw new Error('useAuth must be used within an AuthProvider'); },
45
+ signInWithPhonePassword: async () => { throw new Error('useAuth must be used within an AuthProvider'); },
46
+ requestPhonePasswordReset: async () => { throw new Error('useAuth must be used within an AuthProvider'); },
47
+ resetPasswordWithPhoneOtp: async () => { throw new Error('useAuth must be used within an AuthProvider'); },
43
48
  changePassword: async () => { throw new Error('useAuth must be used within an AuthProvider'); },
44
49
  remediationRequired: null,
45
50
  setRemediationRequired: () => { },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/auth",
3
- "version": "13.1.0",
3
+ "version": "14.0.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Authentication system for Object UI with AuthProvider, useAuth hook, AuthGuard, and form components.",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "better-auth": "^1.6.23",
34
- "@object-ui/types": "13.1.0"
34
+ "@object-ui/types": "14.0.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/react": "19.2.17",