@proveanything/smartlinks-auth-ui 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +9 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/components/SmartlinksAuthUI.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.css.map +1 -1
- package/dist/index.esm.js +127 -18
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +127 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10667,8 +10667,21 @@ class AuthAPI {
|
|
|
10667
10667
|
accountData: data.accountData,
|
|
10668
10668
|
});
|
|
10669
10669
|
}
|
|
10670
|
-
async loginWithGoogle(
|
|
10671
|
-
|
|
10670
|
+
async loginWithGoogle(token, options) {
|
|
10671
|
+
this.log.log('loginWithGoogle called:', {
|
|
10672
|
+
tokenType: options?.tokenType || 'id_token',
|
|
10673
|
+
hasUserInfo: !!options?.googleUserInfo,
|
|
10674
|
+
userEmail: options?.googleUserInfo?.email,
|
|
10675
|
+
tokenLength: token?.length,
|
|
10676
|
+
});
|
|
10677
|
+
// Note: The SDK only supports ID tokens currently
|
|
10678
|
+
// Access tokens from popup flow may fail with "Invalid or expired Google token"
|
|
10679
|
+
if (options?.tokenType === 'access_token') {
|
|
10680
|
+
this.log.warn('Warning: Popup flow sends access_token, but backend expects id_token. This may fail.');
|
|
10681
|
+
this.log.warn('Consider using OneTap flow (default) or updating backend to handle access tokens.');
|
|
10682
|
+
}
|
|
10683
|
+
// Pass token to SDK - backend verifies with Google
|
|
10684
|
+
return smartlinks__namespace.authKit.googleLogin(this.clientId, token);
|
|
10672
10685
|
}
|
|
10673
10686
|
async sendPhoneCode(phoneNumber) {
|
|
10674
10687
|
return smartlinks__namespace.authKit.sendPhoneCode(this.clientId, phoneNumber);
|
|
@@ -11514,6 +11527,33 @@ const loadGoogleIdentityServices = () => {
|
|
|
11514
11527
|
document.head.appendChild(script);
|
|
11515
11528
|
});
|
|
11516
11529
|
};
|
|
11530
|
+
// Helper to convert generic SDK errors to user-friendly messages
|
|
11531
|
+
const getFriendlyErrorMessage = (errorMessage) => {
|
|
11532
|
+
// Check for common HTTP status codes in the error message
|
|
11533
|
+
if (errorMessage.includes('status 400')) {
|
|
11534
|
+
return 'Invalid request. Please check your input and try again.';
|
|
11535
|
+
}
|
|
11536
|
+
if (errorMessage.includes('status 401')) {
|
|
11537
|
+
return 'Invalid credentials. Please check your email and password.';
|
|
11538
|
+
}
|
|
11539
|
+
if (errorMessage.includes('status 403')) {
|
|
11540
|
+
return 'Access denied. You do not have permission to perform this action.';
|
|
11541
|
+
}
|
|
11542
|
+
if (errorMessage.includes('status 404')) {
|
|
11543
|
+
return 'Account not found. Please check your email or create a new account.';
|
|
11544
|
+
}
|
|
11545
|
+
if (errorMessage.includes('status 409')) {
|
|
11546
|
+
return 'This email is already registered.';
|
|
11547
|
+
}
|
|
11548
|
+
if (errorMessage.includes('status 429')) {
|
|
11549
|
+
return 'Too many attempts. Please wait a moment and try again.';
|
|
11550
|
+
}
|
|
11551
|
+
if (errorMessage.includes('status 500') || errorMessage.includes('status 502') || errorMessage.includes('status 503')) {
|
|
11552
|
+
return 'Server error. Please try again later.';
|
|
11553
|
+
}
|
|
11554
|
+
// Return original message if no pattern matches
|
|
11555
|
+
return errorMessage;
|
|
11556
|
+
};
|
|
11517
11557
|
const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAuthSuccess, onAuthError, enabledProviders = ['email', 'google', 'phone'], initialMode = 'login', redirectUrl, theme = 'auto', className, customization, skipConfigFetch = false, minimal = false, logger, }) => {
|
|
11518
11558
|
const [mode, setMode] = React.useState(initialMode);
|
|
11519
11559
|
const [loading, setLoading] = React.useState(false);
|
|
@@ -11878,14 +11918,18 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
11878
11918
|
}
|
|
11879
11919
|
catch (err) {
|
|
11880
11920
|
const errorMessage = err instanceof Error ? err.message : 'Authentication failed';
|
|
11881
|
-
// Check if error is about email already registered
|
|
11882
|
-
|
|
11921
|
+
// Check if error is about email already registered (by content or 409 status code)
|
|
11922
|
+
const isAlreadyRegistered = mode === 'register' && ((errorMessage.toLowerCase().includes('already') && errorMessage.toLowerCase().includes('email')) ||
|
|
11923
|
+
errorMessage.includes('status 409'));
|
|
11924
|
+
if (isAlreadyRegistered) {
|
|
11883
11925
|
setShowResendVerification(true);
|
|
11884
11926
|
setResendEmail(data.email);
|
|
11885
11927
|
setError('This email is already registered. If you didn\'t receive the verification email, you can resend it below.');
|
|
11886
11928
|
}
|
|
11887
11929
|
else {
|
|
11888
|
-
|
|
11930
|
+
// Try to extract a more meaningful error message from status codes
|
|
11931
|
+
const friendlyMessage = getFriendlyErrorMessage(errorMessage);
|
|
11932
|
+
setError(friendlyMessage);
|
|
11889
11933
|
}
|
|
11890
11934
|
onAuthError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
11891
11935
|
}
|
|
@@ -11941,6 +11985,15 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
11941
11985
|
const googleClientId = config?.googleClientId || DEFAULT_GOOGLE_CLIENT_ID;
|
|
11942
11986
|
// Determine OAuth flow: default to 'oneTap' for better UX, but allow 'popup' for iframe compatibility
|
|
11943
11987
|
const oauthFlow = config?.googleOAuthFlow || 'oneTap';
|
|
11988
|
+
// Log Google Auth configuration for debugging
|
|
11989
|
+
log.log('Google Auth initiated:', {
|
|
11990
|
+
googleClientId,
|
|
11991
|
+
oauthFlow,
|
|
11992
|
+
currentOrigin: window.location.origin,
|
|
11993
|
+
currentHref: window.location.href,
|
|
11994
|
+
configGoogleClientId: config?.googleClientId,
|
|
11995
|
+
usingDefaultClientId: !config?.googleClientId,
|
|
11996
|
+
});
|
|
11944
11997
|
setLoading(true);
|
|
11945
11998
|
setError(undefined);
|
|
11946
11999
|
try {
|
|
@@ -11950,35 +12003,87 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
11950
12003
|
if (!google?.accounts) {
|
|
11951
12004
|
throw new Error('Google Identity Services failed to initialize');
|
|
11952
12005
|
}
|
|
12006
|
+
log.log('Google Identity Services loaded, using flow:', oauthFlow);
|
|
11953
12007
|
if (oauthFlow === 'popup') {
|
|
11954
12008
|
// Use OAuth2 popup flow (works in iframes but requires popup permission)
|
|
11955
12009
|
if (!google.accounts.oauth2) {
|
|
11956
12010
|
throw new Error('Google OAuth2 not available');
|
|
11957
12011
|
}
|
|
12012
|
+
log.log('Initializing Google OAuth2 popup flow:', {
|
|
12013
|
+
client_id: googleClientId,
|
|
12014
|
+
scope: 'openid email profile',
|
|
12015
|
+
origin: window.location.origin,
|
|
12016
|
+
});
|
|
11958
12017
|
const client = google.accounts.oauth2.initTokenClient({
|
|
11959
12018
|
client_id: googleClientId,
|
|
11960
12019
|
scope: 'openid email profile',
|
|
11961
12020
|
callback: async (response) => {
|
|
11962
12021
|
try {
|
|
12022
|
+
log.log('Google OAuth2 popup callback received:', {
|
|
12023
|
+
hasAccessToken: !!response.access_token,
|
|
12024
|
+
hasIdToken: !!response.id_token,
|
|
12025
|
+
tokenType: response.token_type,
|
|
12026
|
+
expiresIn: response.expires_in,
|
|
12027
|
+
scope: response.scope,
|
|
12028
|
+
error: response.error,
|
|
12029
|
+
errorDescription: response.error_description,
|
|
12030
|
+
});
|
|
11963
12031
|
if (response.error) {
|
|
11964
12032
|
throw new Error(response.error_description || response.error);
|
|
11965
12033
|
}
|
|
12034
|
+
// OAuth2 popup flow returns access_token, not id_token
|
|
12035
|
+
// We need to use the access token to get user info from Google
|
|
11966
12036
|
const accessToken = response.access_token;
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
if (authResponse.token) {
|
|
11970
|
-
auth.login(authResponse.token, authResponse.user, authResponse.accountData);
|
|
11971
|
-
setAuthSuccess(true);
|
|
11972
|
-
setSuccessMessage('Google login successful!');
|
|
11973
|
-
onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
|
|
12037
|
+
if (!accessToken) {
|
|
12038
|
+
throw new Error('No access token received from Google');
|
|
11974
12039
|
}
|
|
11975
|
-
|
|
11976
|
-
|
|
12040
|
+
log.log('Fetching user info from Google using access token...');
|
|
12041
|
+
// Fetch user info from Google's userinfo endpoint
|
|
12042
|
+
const userInfoResponse = await fetch('https://www.googleapis.com/oauth2/v3/userinfo', {
|
|
12043
|
+
headers: {
|
|
12044
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
12045
|
+
},
|
|
12046
|
+
});
|
|
12047
|
+
if (!userInfoResponse.ok) {
|
|
12048
|
+
throw new Error('Failed to fetch user info from Google');
|
|
11977
12049
|
}
|
|
11978
|
-
|
|
11979
|
-
|
|
11980
|
-
|
|
11981
|
-
|
|
12050
|
+
const userInfo = await userInfoResponse.json();
|
|
12051
|
+
log.log('Google user info retrieved:', {
|
|
12052
|
+
email: userInfo.email,
|
|
12053
|
+
name: userInfo.name,
|
|
12054
|
+
sub: userInfo.sub,
|
|
12055
|
+
});
|
|
12056
|
+
// For popup flow, send the access token to backend
|
|
12057
|
+
// Note: This may fail if backend only supports ID token verification
|
|
12058
|
+
try {
|
|
12059
|
+
const authResponse = await api.loginWithGoogle(accessToken, {
|
|
12060
|
+
googleUserInfo: userInfo,
|
|
12061
|
+
tokenType: 'access_token',
|
|
12062
|
+
});
|
|
12063
|
+
if (authResponse.token) {
|
|
12064
|
+
auth.login(authResponse.token, authResponse.user, authResponse.accountData);
|
|
12065
|
+
setAuthSuccess(true);
|
|
12066
|
+
setSuccessMessage('Google login successful!');
|
|
12067
|
+
onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
|
|
12068
|
+
}
|
|
12069
|
+
else {
|
|
12070
|
+
throw new Error('Authentication failed - no token received');
|
|
12071
|
+
}
|
|
12072
|
+
if (redirectUrl) {
|
|
12073
|
+
setTimeout(() => {
|
|
12074
|
+
window.location.href = redirectUrl;
|
|
12075
|
+
}, 2000);
|
|
12076
|
+
}
|
|
12077
|
+
}
|
|
12078
|
+
catch (apiError) {
|
|
12079
|
+
const errorMessage = apiError instanceof Error ? apiError.message : 'Google login failed';
|
|
12080
|
+
// Check if this is the access token vs ID token mismatch
|
|
12081
|
+
if (errorMessage.includes('Invalid or expired Google token')) {
|
|
12082
|
+
log.error('Popup flow access token rejected by backend. Backend may only support ID tokens.');
|
|
12083
|
+
log.error('User info retrieved from Google:', userInfo);
|
|
12084
|
+
throw new Error('Google authentication failed. The popup flow may not be supported. Please try again or contact support.');
|
|
12085
|
+
}
|
|
12086
|
+
throw apiError;
|
|
11982
12087
|
}
|
|
11983
12088
|
setLoading(false);
|
|
11984
12089
|
}
|
|
@@ -11994,6 +12099,10 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
11994
12099
|
}
|
|
11995
12100
|
else {
|
|
11996
12101
|
// Use One Tap / Sign-In button flow (smoother UX but doesn't work in iframes)
|
|
12102
|
+
log.log('Initializing Google OneTap flow:', {
|
|
12103
|
+
client_id: googleClientId,
|
|
12104
|
+
origin: window.location.origin,
|
|
12105
|
+
});
|
|
11997
12106
|
google.accounts.id.initialize({
|
|
11998
12107
|
client_id: googleClientId,
|
|
11999
12108
|
callback: async (response) => {
|