@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.esm.js
CHANGED
|
@@ -10646,8 +10646,21 @@ class AuthAPI {
|
|
|
10646
10646
|
accountData: data.accountData,
|
|
10647
10647
|
});
|
|
10648
10648
|
}
|
|
10649
|
-
async loginWithGoogle(
|
|
10650
|
-
|
|
10649
|
+
async loginWithGoogle(token, options) {
|
|
10650
|
+
this.log.log('loginWithGoogle called:', {
|
|
10651
|
+
tokenType: options?.tokenType || 'id_token',
|
|
10652
|
+
hasUserInfo: !!options?.googleUserInfo,
|
|
10653
|
+
userEmail: options?.googleUserInfo?.email,
|
|
10654
|
+
tokenLength: token?.length,
|
|
10655
|
+
});
|
|
10656
|
+
// Note: The SDK only supports ID tokens currently
|
|
10657
|
+
// Access tokens from popup flow may fail with "Invalid or expired Google token"
|
|
10658
|
+
if (options?.tokenType === 'access_token') {
|
|
10659
|
+
this.log.warn('Warning: Popup flow sends access_token, but backend expects id_token. This may fail.');
|
|
10660
|
+
this.log.warn('Consider using OneTap flow (default) or updating backend to handle access tokens.');
|
|
10661
|
+
}
|
|
10662
|
+
// Pass token to SDK - backend verifies with Google
|
|
10663
|
+
return smartlinks.authKit.googleLogin(this.clientId, token);
|
|
10651
10664
|
}
|
|
10652
10665
|
async sendPhoneCode(phoneNumber) {
|
|
10653
10666
|
return smartlinks.authKit.sendPhoneCode(this.clientId, phoneNumber);
|
|
@@ -11493,6 +11506,33 @@ const loadGoogleIdentityServices = () => {
|
|
|
11493
11506
|
document.head.appendChild(script);
|
|
11494
11507
|
});
|
|
11495
11508
|
};
|
|
11509
|
+
// Helper to convert generic SDK errors to user-friendly messages
|
|
11510
|
+
const getFriendlyErrorMessage = (errorMessage) => {
|
|
11511
|
+
// Check for common HTTP status codes in the error message
|
|
11512
|
+
if (errorMessage.includes('status 400')) {
|
|
11513
|
+
return 'Invalid request. Please check your input and try again.';
|
|
11514
|
+
}
|
|
11515
|
+
if (errorMessage.includes('status 401')) {
|
|
11516
|
+
return 'Invalid credentials. Please check your email and password.';
|
|
11517
|
+
}
|
|
11518
|
+
if (errorMessage.includes('status 403')) {
|
|
11519
|
+
return 'Access denied. You do not have permission to perform this action.';
|
|
11520
|
+
}
|
|
11521
|
+
if (errorMessage.includes('status 404')) {
|
|
11522
|
+
return 'Account not found. Please check your email or create a new account.';
|
|
11523
|
+
}
|
|
11524
|
+
if (errorMessage.includes('status 409')) {
|
|
11525
|
+
return 'This email is already registered.';
|
|
11526
|
+
}
|
|
11527
|
+
if (errorMessage.includes('status 429')) {
|
|
11528
|
+
return 'Too many attempts. Please wait a moment and try again.';
|
|
11529
|
+
}
|
|
11530
|
+
if (errorMessage.includes('status 500') || errorMessage.includes('status 502') || errorMessage.includes('status 503')) {
|
|
11531
|
+
return 'Server error. Please try again later.';
|
|
11532
|
+
}
|
|
11533
|
+
// Return original message if no pattern matches
|
|
11534
|
+
return errorMessage;
|
|
11535
|
+
};
|
|
11496
11536
|
const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAuthSuccess, onAuthError, enabledProviders = ['email', 'google', 'phone'], initialMode = 'login', redirectUrl, theme = 'auto', className, customization, skipConfigFetch = false, minimal = false, logger, }) => {
|
|
11497
11537
|
const [mode, setMode] = useState(initialMode);
|
|
11498
11538
|
const [loading, setLoading] = useState(false);
|
|
@@ -11857,14 +11897,18 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
11857
11897
|
}
|
|
11858
11898
|
catch (err) {
|
|
11859
11899
|
const errorMessage = err instanceof Error ? err.message : 'Authentication failed';
|
|
11860
|
-
// Check if error is about email already registered
|
|
11861
|
-
|
|
11900
|
+
// Check if error is about email already registered (by content or 409 status code)
|
|
11901
|
+
const isAlreadyRegistered = mode === 'register' && ((errorMessage.toLowerCase().includes('already') && errorMessage.toLowerCase().includes('email')) ||
|
|
11902
|
+
errorMessage.includes('status 409'));
|
|
11903
|
+
if (isAlreadyRegistered) {
|
|
11862
11904
|
setShowResendVerification(true);
|
|
11863
11905
|
setResendEmail(data.email);
|
|
11864
11906
|
setError('This email is already registered. If you didn\'t receive the verification email, you can resend it below.');
|
|
11865
11907
|
}
|
|
11866
11908
|
else {
|
|
11867
|
-
|
|
11909
|
+
// Try to extract a more meaningful error message from status codes
|
|
11910
|
+
const friendlyMessage = getFriendlyErrorMessage(errorMessage);
|
|
11911
|
+
setError(friendlyMessage);
|
|
11868
11912
|
}
|
|
11869
11913
|
onAuthError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
11870
11914
|
}
|
|
@@ -11920,6 +11964,15 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
11920
11964
|
const googleClientId = config?.googleClientId || DEFAULT_GOOGLE_CLIENT_ID;
|
|
11921
11965
|
// Determine OAuth flow: default to 'oneTap' for better UX, but allow 'popup' for iframe compatibility
|
|
11922
11966
|
const oauthFlow = config?.googleOAuthFlow || 'oneTap';
|
|
11967
|
+
// Log Google Auth configuration for debugging
|
|
11968
|
+
log.log('Google Auth initiated:', {
|
|
11969
|
+
googleClientId,
|
|
11970
|
+
oauthFlow,
|
|
11971
|
+
currentOrigin: window.location.origin,
|
|
11972
|
+
currentHref: window.location.href,
|
|
11973
|
+
configGoogleClientId: config?.googleClientId,
|
|
11974
|
+
usingDefaultClientId: !config?.googleClientId,
|
|
11975
|
+
});
|
|
11923
11976
|
setLoading(true);
|
|
11924
11977
|
setError(undefined);
|
|
11925
11978
|
try {
|
|
@@ -11929,35 +11982,87 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
11929
11982
|
if (!google?.accounts) {
|
|
11930
11983
|
throw new Error('Google Identity Services failed to initialize');
|
|
11931
11984
|
}
|
|
11985
|
+
log.log('Google Identity Services loaded, using flow:', oauthFlow);
|
|
11932
11986
|
if (oauthFlow === 'popup') {
|
|
11933
11987
|
// Use OAuth2 popup flow (works in iframes but requires popup permission)
|
|
11934
11988
|
if (!google.accounts.oauth2) {
|
|
11935
11989
|
throw new Error('Google OAuth2 not available');
|
|
11936
11990
|
}
|
|
11991
|
+
log.log('Initializing Google OAuth2 popup flow:', {
|
|
11992
|
+
client_id: googleClientId,
|
|
11993
|
+
scope: 'openid email profile',
|
|
11994
|
+
origin: window.location.origin,
|
|
11995
|
+
});
|
|
11937
11996
|
const client = google.accounts.oauth2.initTokenClient({
|
|
11938
11997
|
client_id: googleClientId,
|
|
11939
11998
|
scope: 'openid email profile',
|
|
11940
11999
|
callback: async (response) => {
|
|
11941
12000
|
try {
|
|
12001
|
+
log.log('Google OAuth2 popup callback received:', {
|
|
12002
|
+
hasAccessToken: !!response.access_token,
|
|
12003
|
+
hasIdToken: !!response.id_token,
|
|
12004
|
+
tokenType: response.token_type,
|
|
12005
|
+
expiresIn: response.expires_in,
|
|
12006
|
+
scope: response.scope,
|
|
12007
|
+
error: response.error,
|
|
12008
|
+
errorDescription: response.error_description,
|
|
12009
|
+
});
|
|
11942
12010
|
if (response.error) {
|
|
11943
12011
|
throw new Error(response.error_description || response.error);
|
|
11944
12012
|
}
|
|
12013
|
+
// OAuth2 popup flow returns access_token, not id_token
|
|
12014
|
+
// We need to use the access token to get user info from Google
|
|
11945
12015
|
const accessToken = response.access_token;
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
if (authResponse.token) {
|
|
11949
|
-
auth.login(authResponse.token, authResponse.user, authResponse.accountData);
|
|
11950
|
-
setAuthSuccess(true);
|
|
11951
|
-
setSuccessMessage('Google login successful!');
|
|
11952
|
-
onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
|
|
12016
|
+
if (!accessToken) {
|
|
12017
|
+
throw new Error('No access token received from Google');
|
|
11953
12018
|
}
|
|
11954
|
-
|
|
11955
|
-
|
|
12019
|
+
log.log('Fetching user info from Google using access token...');
|
|
12020
|
+
// Fetch user info from Google's userinfo endpoint
|
|
12021
|
+
const userInfoResponse = await fetch('https://www.googleapis.com/oauth2/v3/userinfo', {
|
|
12022
|
+
headers: {
|
|
12023
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
12024
|
+
},
|
|
12025
|
+
});
|
|
12026
|
+
if (!userInfoResponse.ok) {
|
|
12027
|
+
throw new Error('Failed to fetch user info from Google');
|
|
11956
12028
|
}
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
|
|
12029
|
+
const userInfo = await userInfoResponse.json();
|
|
12030
|
+
log.log('Google user info retrieved:', {
|
|
12031
|
+
email: userInfo.email,
|
|
12032
|
+
name: userInfo.name,
|
|
12033
|
+
sub: userInfo.sub,
|
|
12034
|
+
});
|
|
12035
|
+
// For popup flow, send the access token to backend
|
|
12036
|
+
// Note: This may fail if backend only supports ID token verification
|
|
12037
|
+
try {
|
|
12038
|
+
const authResponse = await api.loginWithGoogle(accessToken, {
|
|
12039
|
+
googleUserInfo: userInfo,
|
|
12040
|
+
tokenType: 'access_token',
|
|
12041
|
+
});
|
|
12042
|
+
if (authResponse.token) {
|
|
12043
|
+
auth.login(authResponse.token, authResponse.user, authResponse.accountData);
|
|
12044
|
+
setAuthSuccess(true);
|
|
12045
|
+
setSuccessMessage('Google login successful!');
|
|
12046
|
+
onAuthSuccess(authResponse.token, authResponse.user, authResponse.accountData);
|
|
12047
|
+
}
|
|
12048
|
+
else {
|
|
12049
|
+
throw new Error('Authentication failed - no token received');
|
|
12050
|
+
}
|
|
12051
|
+
if (redirectUrl) {
|
|
12052
|
+
setTimeout(() => {
|
|
12053
|
+
window.location.href = redirectUrl;
|
|
12054
|
+
}, 2000);
|
|
12055
|
+
}
|
|
12056
|
+
}
|
|
12057
|
+
catch (apiError) {
|
|
12058
|
+
const errorMessage = apiError instanceof Error ? apiError.message : 'Google login failed';
|
|
12059
|
+
// Check if this is the access token vs ID token mismatch
|
|
12060
|
+
if (errorMessage.includes('Invalid or expired Google token')) {
|
|
12061
|
+
log.error('Popup flow access token rejected by backend. Backend may only support ID tokens.');
|
|
12062
|
+
log.error('User info retrieved from Google:', userInfo);
|
|
12063
|
+
throw new Error('Google authentication failed. The popup flow may not be supported. Please try again or contact support.');
|
|
12064
|
+
}
|
|
12065
|
+
throw apiError;
|
|
11961
12066
|
}
|
|
11962
12067
|
setLoading(false);
|
|
11963
12068
|
}
|
|
@@ -11973,6 +12078,10 @@ const SmartlinksAuthUI = ({ apiEndpoint, clientId, clientName, accountData, onAu
|
|
|
11973
12078
|
}
|
|
11974
12079
|
else {
|
|
11975
12080
|
// Use One Tap / Sign-In button flow (smoother UX but doesn't work in iframes)
|
|
12081
|
+
log.log('Initializing Google OneTap flow:', {
|
|
12082
|
+
client_id: googleClientId,
|
|
12083
|
+
origin: window.location.origin,
|
|
12084
|
+
});
|
|
11976
12085
|
google.accounts.id.initialize({
|
|
11977
12086
|
client_id: googleClientId,
|
|
11978
12087
|
callback: async (response) => {
|