@proveanything/smartlinks-auth-ui 0.1.43 → 0.1.45

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.
@@ -1 +1 @@
1
- {"version":3,"file":"SmartlinksAuthUI.d.ts","sourceRoot":"","sources":["../../src/components/SmartlinksAuthUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAW5D,OAAO,KAAK,EAAE,qBAAqB,EAAyF,MAAM,UAAU,CAAC;AAgI7I,QAAA,MAAM,mBAAmB,QAAa,OAAO,CAAC,IAAI,CA+CjD,CAAC;AAyFF,OAAO,EAAE,mBAAmB,EAAE,CAAC;AA8B/B,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAulD5D,CAAC"}
1
+ {"version":3,"file":"SmartlinksAuthUI.d.ts","sourceRoot":"","sources":["../../src/components/SmartlinksAuthUI.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAW5D,OAAO,KAAK,EAAE,qBAAqB,EAAyF,MAAM,UAAU,CAAC;AAgI7I,QAAA,MAAM,mBAAmB,QAAa,OAAO,CAAC,IAAI,CA+CjD,CAAC;AAyFF,OAAO,EAAE,mBAAmB,EAAE,CAAC;AA8B/B,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA8oD5D,CAAC"}
@@ -15,7 +15,7 @@ interface AuthContextValue {
15
15
  contactId: string | null;
16
16
  getContact: (forceRefresh?: boolean) => Promise<ContactResponse | null>;
17
17
  updateContactCustomFields: (customFields: Record<string, any>) => Promise<ContactResponse>;
18
- login: (token: string, user: AuthUser, accountData?: Record<string, any>, isNewUser?: boolean, expiresAt?: number) => Promise<void>;
18
+ login: (token: string, user: AuthUser, accountData?: Record<string, any>, isNewUser?: boolean, expiresAt?: number, waitForParentAck?: boolean) => Promise<void>;
19
19
  logout: () => Promise<void>;
20
20
  getToken: () => Promise<string | null>;
21
21
  getTokenInfo: () => Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../../src/context/AuthContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8E,MAAM,OAAO,CAAC;AAGnG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGjE,OAAO,KAAK,EAAE,QAAQ,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAErF,UAAU,gBAAgB;IACxB,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IAGnB,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IACxE,yBAAyB,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAG3F,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpI,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,YAAY,EAAE,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC5F,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACrE,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACnD,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,iBAAiB,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,MAAM,IAAI,CAAC;IACrE,iBAAiB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3C;AAID,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA03BpD,CAAC;AAEF,eAAO,MAAM,OAAO,QAAO,gBAM1B,CAAC"}
1
+ {"version":3,"file":"AuthContext.d.ts","sourceRoot":"","sources":["../../src/context/AuthContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8E,MAAM,OAAO,CAAC;AAGnG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGjE,OAAO,KAAK,EAAE,QAAQ,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAErF,UAAU,gBAAgB;IACxB,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACxC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IAGnB,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IACxE,yBAAyB,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAG3F,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChK,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,YAAY,EAAE,MAAM,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC5F,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,UAAU,EAAE,CAAC,YAAY,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACrE,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACnD,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,iBAAiB,EAAE,CAAC,QAAQ,EAAE,uBAAuB,KAAK,MAAM,IAAI,CAAC;IACrE,iBAAiB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3C;AAID,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAq7BpD,CAAC;AAEF,eAAO,MAAM,OAAO,QAAO,gBAM1B,CAAC"}
package/dist/index.esm.js CHANGED
@@ -11840,7 +11840,42 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11840
11840
  unsubscribe();
11841
11841
  };
11842
11842
  }, [proxyMode, notifyAuthStateChange]);
11843
- const login = useCallback(async (authToken, authUser, authAccountData, isNewUser, expiresAt) => {
11843
+ // Helper: Send login to parent and wait for acknowledgment
11844
+ // Used for deep-link flows (email verification, magic link) where we need to ensure
11845
+ // the parent has persisted the session before redirecting (which causes page reload)
11846
+ const notifyParentLoginAndWait = async (authToken, authUser, authAccountData, timeoutMs = 5000) => {
11847
+ return new Promise((resolve) => {
11848
+ const messageId = `login-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
11849
+ const handleAck = (event) => {
11850
+ if (event.data?.type === 'smartlinks:authkit:login-acknowledged' &&
11851
+ event.data?.messageId === messageId) {
11852
+ window.removeEventListener('message', handleAck);
11853
+ clearTimeout(timeoutHandle);
11854
+ if (event.data.success) {
11855
+ console.log('[AuthContext] Parent acknowledged login successfully');
11856
+ }
11857
+ else {
11858
+ console.warn('[AuthContext] Parent rejected login:', event.data.error);
11859
+ }
11860
+ resolve();
11861
+ }
11862
+ };
11863
+ const timeoutHandle = setTimeout(() => {
11864
+ window.removeEventListener('message', handleAck);
11865
+ console.warn('[AuthContext] Parent login acknowledgment timed out, proceeding anyway');
11866
+ resolve(); // Don't block forever - fallback to current behavior
11867
+ }, timeoutMs);
11868
+ window.addEventListener('message', handleAck);
11869
+ console.log('[AuthContext] Sending login to parent, awaiting acknowledgment:', messageId);
11870
+ iframe.sendParentCustom('smartlinks:authkit:login', {
11871
+ messageId,
11872
+ token: authToken,
11873
+ user: authUser,
11874
+ accountData: authAccountData || null
11875
+ });
11876
+ });
11877
+ };
11878
+ const login = useCallback(async (authToken, authUser, authAccountData, isNewUser, expiresAt, waitForParentAck) => {
11844
11879
  try {
11845
11880
  // Only persist to storage in standalone mode
11846
11881
  if (!proxyMode) {
@@ -11861,12 +11896,20 @@ collectionId, enableContactSync, enableInteractionTracking, interactionAppId, in
11861
11896
  pendingVerificationRef.current = false;
11862
11897
  // Cross-iframe auth state synchronization
11863
11898
  if (iframe.isIframe()) {
11864
- console.log('[AuthContext] Notifying parent of login via postMessage');
11865
- iframe.sendParentCustom('smartlinks:authkit:login', {
11866
- token: authToken,
11867
- user: authUser,
11868
- accountData: authAccountData || null
11869
- });
11899
+ if (waitForParentAck) {
11900
+ // For deep-link flows: wait for parent to validate and persist session before redirect
11901
+ console.log('[AuthContext] Notifying parent of login and waiting for acknowledgment');
11902
+ await notifyParentLoginAndWait(authToken, authUser, authAccountData);
11903
+ }
11904
+ else {
11905
+ // For interactive flows: fire-and-forget is fine (no redirect follows)
11906
+ console.log('[AuthContext] Notifying parent of login via postMessage');
11907
+ iframe.sendParentCustom('smartlinks:authkit:login', {
11908
+ token: authToken,
11909
+ user: authUser,
11910
+ accountData: authAccountData || null
11911
+ });
11912
+ }
11870
11913
  }
11871
11914
  notifyAuthStateChange('LOGIN', authUser, authToken, authAccountData || null, null, true);
11872
11915
  // Sync contact (non-blocking)
@@ -12192,7 +12235,7 @@ const useAuth = () => {
12192
12235
  };
12193
12236
 
12194
12237
  // VERSION: Update this when making changes to help identify which version is running
12195
- const AUTH_UI_VERSION = '37';
12238
+ const AUTH_UI_VERSION = '41';
12196
12239
  const LOG_PREFIX = `[SmartlinksAuthUI:v${AUTH_UI_VERSION}]`;
12197
12240
  // Helper to calculate expiration from AuthResponse
12198
12241
  const getExpirationFromResponse = (response) => {
@@ -12707,7 +12750,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12707
12750
  const authResponse = await api.loginWithGoogle(result.idToken);
12708
12751
  if (authResponse.token) {
12709
12752
  console.log(`${LOG_PREFIX} 🔇 Silent sign-in successful!`);
12710
- auth.login(authResponse.token, authResponse.user, authResponse.accountData, false, getExpirationFromResponse(authResponse));
12753
+ await auth.login(authResponse.token, authResponse.user, authResponse.accountData, false, getExpirationFromResponse(authResponse));
12711
12754
  setAuthSuccess(true);
12712
12755
  setSuccessMessage('Signed in automatically with Google!');
12713
12756
  onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
@@ -12779,18 +12822,30 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12779
12822
  const verificationMode = response.emailVerificationMode || config?.emailVerification?.mode || 'verify-auto-login';
12780
12823
  if ((verificationMode === 'verify-auto-login' || verificationMode === 'immediate') && response.token) {
12781
12824
  // Auto-login modes: Log the user in immediately if token is provided
12782
- auth.login(response.token, response.user, response.accountData, true, getExpirationFromResponse(response));
12783
- setAuthSuccess(true);
12784
- setSuccessMessage('Email verified successfully! You are now logged in.');
12785
- onAuthSuccess(response.token, response.user, response.accountData);
12786
- // Clear the URL parameters
12825
+ // In proxy mode, wait for parent to acknowledge (validate & persist) before redirect
12826
+ // MUST await to ensure session is ready before any redirect
12827
+ await auth.login(response.token, response.user, response.accountData, true, getExpirationFromResponse(response), proxyMode // waitForParentAck - ensures parent has validated/persisted before redirect
12828
+ );
12829
+ // Clean URL parameters regardless of redirect
12787
12830
  const cleanUrl = window.location.href.split('?')[0];
12788
12831
  window.history.replaceState({}, document.title, cleanUrl);
12789
- // For email verification deep links, redirect immediately if configured
12790
- // (user came from an email link, so redirect is expected behavior)
12791
12832
  if (redirectUrl) {
12833
+ // Redirect to clean URL and resume flow
12834
+ // In proxy mode: parent already validated & persisted via acknowledgment in auth.login()
12835
+ // In standalone mode: session saved to IndexedDB, AuthContext will restore on reload
12836
+ // Either way: DON'T call onAuthSuccess (redirect wipes page state)
12837
+ log.log('Email verification complete, redirecting to:', redirectUrl);
12792
12838
  performRedirect(redirectUrl, 'email-verified');
12793
12839
  }
12840
+ else {
12841
+ // No redirect configured: show success UI
12842
+ setAuthSuccess(true);
12843
+ setSuccessMessage('Email verified successfully! You are now logged in.');
12844
+ if (!proxyMode) {
12845
+ // Only call onAuthSuccess in standalone mode (proxy mode used postMessage)
12846
+ onAuthSuccess(response.token, response.user, response.accountData);
12847
+ }
12848
+ }
12794
12849
  }
12795
12850
  else {
12796
12851
  // verify-manual-login mode or no token: Show success but require manual login
@@ -12828,18 +12883,26 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12828
12883
  const response = await api.verifyMagicLink(token);
12829
12884
  // Auto-login with magic link if token is provided
12830
12885
  if (response.token) {
12831
- auth.login(response.token, response.user, response.accountData, true, getExpirationFromResponse(response));
12832
- setAuthSuccess(true);
12833
- setSuccessMessage('Magic link verified! You are now logged in.');
12834
- onAuthSuccess(response.token, response.user, response.accountData);
12835
- // Clear the URL parameters
12886
+ // In proxy mode, wait for parent to acknowledge (validate & persist) before redirect
12887
+ // MUST await to ensure session is ready before any redirect
12888
+ await auth.login(response.token, response.user, response.accountData, true, getExpirationFromResponse(response), proxyMode // waitForParentAck
12889
+ );
12890
+ // Clean URL parameters regardless of redirect
12836
12891
  const cleanUrl = window.location.href.split('?')[0];
12837
12892
  window.history.replaceState({}, document.title, cleanUrl);
12838
- // For magic link deep links, redirect immediately if configured
12839
- // (user came from an email link, so redirect is expected behavior)
12840
12893
  if (redirectUrl) {
12894
+ // Redirect to clean URL and resume flow
12895
+ log.log('Magic link verification complete, redirecting to:', redirectUrl);
12841
12896
  performRedirect(redirectUrl, 'magic-link');
12842
12897
  }
12898
+ else {
12899
+ // No redirect configured: show success UI
12900
+ setAuthSuccess(true);
12901
+ setSuccessMessage('Magic link verified! You are now logged in.');
12902
+ if (!proxyMode) {
12903
+ onAuthSuccess(response.token, response.user, response.accountData);
12904
+ }
12905
+ }
12843
12906
  }
12844
12907
  else {
12845
12908
  throw new Error('Authentication failed - no token received');
@@ -12897,7 +12960,8 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12897
12960
  // Exchange authorization code for tokens
12898
12961
  const response = await api.loginWithGoogleCode(code, redirectUri);
12899
12962
  if (response.token) {
12900
- auth.login(response.token, response.user, response.accountData, response.isNewUser, getExpirationFromResponse(response));
12963
+ // Await login to ensure token is persisted before any navigation
12964
+ await auth.login(response.token, response.user, response.accountData, response.isNewUser, getExpirationFromResponse(response));
12901
12965
  setAuthSuccess(true);
12902
12966
  setSuccessMessage('Google login successful!');
12903
12967
  onAuthSuccess(response.token, response.user, response.accountData);
@@ -12945,7 +13009,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12945
13009
  // Handle different verification modes
12946
13010
  if (verificationMode === 'immediate' && response.token) {
12947
13011
  // Immediate mode: Log in right away if token is provided (isNewUser=true for registration)
12948
- auth.login(response.token, response.user, response.accountData, true, getExpirationFromResponse(response));
13012
+ await auth.login(response.token, response.user, response.accountData, true, getExpirationFromResponse(response));
12949
13013
  setAuthSuccess(true);
12950
13014
  const deadline = response.emailVerificationDeadline
12951
13015
  ? new Date(response.emailVerificationDeadline).toLocaleString()
@@ -12999,7 +13063,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
12999
13063
  if (response.requiresEmailVerification) {
13000
13064
  throw new Error('Please verify your email before logging in. Check your inbox for the verification link.');
13001
13065
  }
13002
- auth.login(response.token, response.user, response.accountData, false, getExpirationFromResponse(response));
13066
+ await auth.login(response.token, response.user, response.accountData, false, getExpirationFromResponse(response));
13003
13067
  setAuthSuccess(true);
13004
13068
  setSuccessMessage('Login successful!');
13005
13069
  onAuthSuccess(response.token, response.user, response.accountData);
@@ -13059,14 +13123,23 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13059
13123
  setLoading(true);
13060
13124
  setError(undefined);
13061
13125
  try {
13062
- await api.requestPasswordReset(resetRequestEmail, getRedirectUrl());
13063
- setAuthSuccess(true);
13064
- setSuccessMessage('Password reset email sent! Please check your inbox.');
13126
+ const result = await api.requestPasswordReset(resetRequestEmail, getRedirectUrl());
13127
+ // Use resetSuccess (not authSuccess) to show password reset confirmation, not "Login successful"
13128
+ setResetSuccess(true);
13129
+ // Use backend message if available, otherwise default
13130
+ setSuccessMessage(result?.message || 'Password reset email sent! Please check your inbox.');
13065
13131
  setShowRequestNewReset(false);
13066
13132
  setResetRequestEmail('');
13067
13133
  }
13068
13134
  catch (err) {
13069
- const errorMessage = err instanceof Error ? err.message : 'Failed to send password reset email';
13135
+ // Extract error message - handle both Error objects and API error responses
13136
+ let errorMessage = 'Failed to send password reset email';
13137
+ if (err instanceof Error) {
13138
+ errorMessage = err.message;
13139
+ }
13140
+ else if (err && typeof err === 'object' && 'message' in err) {
13141
+ errorMessage = err.message;
13142
+ }
13070
13143
  setError(errorMessage);
13071
13144
  onAuthError?.(err instanceof Error ? err : new Error(errorMessage));
13072
13145
  }
@@ -13157,7 +13230,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13157
13230
  });
13158
13231
  if (authResponse.token) {
13159
13232
  console.log(`${LOG_PREFIX} 🎉 Login successful! Calling auth.login and onAuthSuccess...`);
13160
- auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
13233
+ await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
13161
13234
  setAuthSuccess(true);
13162
13235
  setSuccessMessage('Google login successful!');
13163
13236
  onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
@@ -13316,7 +13389,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13316
13389
  });
13317
13390
  if (authResponse.token) {
13318
13391
  // Google OAuth can be login or signup - use isNewUser flag from backend if available
13319
- auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
13392
+ await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
13320
13393
  setAuthSuccess(true);
13321
13394
  setSuccessMessage('Google login successful!');
13322
13395
  onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
@@ -13362,7 +13435,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13362
13435
  const authResponse = await api.loginWithGoogle(idToken);
13363
13436
  if (authResponse.token) {
13364
13437
  // Google OAuth can be login or signup - use isNewUser flag from backend if available
13365
- auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
13438
+ await auth.login(authResponse.token, authResponse.user, authResponse.accountData, authResponse.isNewUser, getExpirationFromResponse(authResponse));
13366
13439
  setAuthSuccess(true);
13367
13440
  setSuccessMessage('Google login successful!');
13368
13441
  onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
@@ -13419,11 +13492,22 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13419
13492
  // Update auth context with account data if token is provided
13420
13493
  if (response.token) {
13421
13494
  // Phone auth can be login or signup - use isNewUser flag from backend if available
13422
- auth.login(response.token, response.user, response.accountData, response.isNewUser, getExpirationFromResponse(response));
13423
- onAuthSuccess(response.token, response.user, response.accountData);
13495
+ // In proxy mode, wait for parent to acknowledge (validate & persist) before redirect
13496
+ await auth.login(response.token, response.user, response.accountData, response.isNewUser, getExpirationFromResponse(response), proxyMode // waitForParentAck
13497
+ );
13424
13498
  if (redirectUrl) {
13499
+ // Redirect to clean URL and resume flow
13500
+ log.log('Phone verification complete, redirecting to:', redirectUrl);
13425
13501
  performRedirect(redirectUrl, 'phone-verified');
13426
13502
  }
13503
+ else {
13504
+ // No redirect configured: show success UI
13505
+ setAuthSuccess(true);
13506
+ setSuccessMessage('Phone verified! You are now logged in.');
13507
+ if (!proxyMode) {
13508
+ onAuthSuccess(response.token, response.user, response.accountData);
13509
+ }
13510
+ }
13427
13511
  }
13428
13512
  else {
13429
13513
  throw new Error('Authentication failed - no token received');
@@ -13461,7 +13545,7 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
13461
13545
  try {
13462
13546
  const loginResponse = await api.login(resetEmail, emailOrPassword);
13463
13547
  if (loginResponse.token) {
13464
- auth.login(loginResponse.token, loginResponse.user, loginResponse.accountData, false);
13548
+ await auth.login(loginResponse.token, loginResponse.user, loginResponse.accountData, false);
13465
13549
  setAuthSuccess(true);
13466
13550
  setSuccessMessage('Password reset successful! You are now signed in.');
13467
13551
  onAuthSuccess(loginResponse.token, loginResponse.user, loginResponse.accountData);