App login is working
This commit is contained in:
@@ -1,119 +1,98 @@
|
||||
let googleClient = null;
|
||||
let isSigningIn = false;
|
||||
let googleInitialized = false;
|
||||
|
||||
function waitForGoogleApi() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (window.google?.accounts?.oauth2) {
|
||||
resolve(window.google);
|
||||
return;
|
||||
}
|
||||
|
||||
const maxAttempts = 20;
|
||||
let attempts = 0;
|
||||
|
||||
const checkGoogle = setInterval(() => {
|
||||
attempts++;
|
||||
if (window.google?.accounts?.oauth2) {
|
||||
clearInterval(checkGoogle);
|
||||
resolve(window.google);
|
||||
} else if (attempts >= maxAttempts) {
|
||||
clearInterval(checkGoogle);
|
||||
reject(new Error('Google OAuth2 API failed to load within the timeout period'));
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
async function handleAuthError(error, context = '') {
|
||||
const errorMessage = error?.message || error?.type || error?.toString() || 'Unknown error';
|
||||
const fullError = `${context}: ${errorMessage}`;
|
||||
console.error('Google Auth Error:', { context, error, fullError });
|
||||
await DotNet.invokeMethodAsync('BimAI.UI.Shared', 'OnGoogleSignInError', fullError);
|
||||
}
|
||||
|
||||
async function fetchUserInfo(accessToken) {
|
||||
const response = await fetch('https://www.googleapis.com/oauth2/v3/userinfo', {
|
||||
headers: { 'Authorization': `Bearer ${accessToken}` }
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error('Failed to fetch user info:', errorText);
|
||||
await DotNet.invokeMethodAsync('BimAI.UI.Shared', 'OnGoogleSignInError',
|
||||
`Failed to fetch user info: HTTP ${response.status}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
window.initGoogleSignIn = async function(clientId) {
|
||||
if (googleClient) {
|
||||
return googleClient;
|
||||
window.initGoogleSignIn = function(clientId) {
|
||||
if (googleInitialized) {
|
||||
console.log("Google Sign-In already initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const google = await waitForGoogleApi();
|
||||
|
||||
googleClient = google.accounts.oauth2.initTokenClient({
|
||||
client_id: clientId,
|
||||
scope: 'email profile',
|
||||
callback: async (tokenResponse) => {
|
||||
try {
|
||||
if (tokenResponse.error) {
|
||||
console.error('Token response error:', tokenResponse.error);
|
||||
await DotNet.invokeMethodAsync('BimAI.UI.Shared', 'OnGoogleSignInError',
|
||||
tokenResponse.error);
|
||||
return;
|
||||
}
|
||||
|
||||
const userInfo = await fetchUserInfo(tokenResponse.access_token);
|
||||
if (!userInfo) return;
|
||||
|
||||
await DotNet.invokeMethodAsync('BimAI.UI.Shared', 'OnGoogleSignInSuccess',
|
||||
tokenResponse.access_token,
|
||||
userInfo.name || '',
|
||||
userInfo.email || '',
|
||||
userInfo.picture || ''
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Callback error:', error);
|
||||
await DotNet.invokeMethodAsync('BimAI.UI.Shared', 'OnGoogleSignInError',
|
||||
error.message || 'Unknown callback error');
|
||||
} finally {
|
||||
isSigningIn = false;
|
||||
}
|
||||
},
|
||||
error_callback: async (error) => {
|
||||
console.error('OAuth flow error:', error);
|
||||
await DotNet.invokeMethodAsync('BimAI.UI.Shared', 'OnGoogleSignInError',
|
||||
error.type || 'OAuth flow error');
|
||||
isSigningIn = false;
|
||||
}
|
||||
});
|
||||
|
||||
return googleClient;
|
||||
} catch (error) {
|
||||
console.error('Initiaxcrun xctrace list deviceslization error:', error);
|
||||
await DotNet.invokeMethodAsync('BimAI.UI.Shared', 'OnGoogleSignInError',
|
||||
error.message || 'Failed to initialize Google Sign-In');
|
||||
isSigningIn = false;
|
||||
}
|
||||
console.log("🔐 Initializing Google Sign-In (ID Token flow) with clientId:", clientId);
|
||||
|
||||
// Używamy google.accounts.id - zwraca ID token (JWT credential)
|
||||
google.accounts.id.initialize({
|
||||
client_id: clientId,
|
||||
callback: handleCredentialResponse,
|
||||
auto_select: false,
|
||||
cancel_on_tap_outside: true
|
||||
});
|
||||
|
||||
googleInitialized = true;
|
||||
console.log("✅ Google Sign-In initialized successfully");
|
||||
};
|
||||
|
||||
window.requestGoogleSignIn = async function() {
|
||||
if (isSigningIn) {
|
||||
console.log('Sign-in already in progress');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!googleClient) {
|
||||
console.error('Google Sign-In not initialized');
|
||||
await DotNet.invokeMethodAsync('BimAI.UI.Shared', 'OnGoogleSignInError',
|
||||
'Google Sign-In not initialized. Call initGoogleSignIn first.');
|
||||
return;
|
||||
}
|
||||
window.requestGoogleSignIn = function() {
|
||||
console.log("🚀 Requesting Google Sign-In...");
|
||||
|
||||
isSigningIn = true;
|
||||
googleClient.requestAccessToken();
|
||||
};
|
||||
// Pokaż One Tap prompt
|
||||
google.accounts.id.prompt((notification) => {
|
||||
if (notification.isNotDisplayed()) {
|
||||
console.warn("⚠️ One Tap not displayed:", notification.getNotDisplayedReason());
|
||||
} else if (notification.isSkippedMoment()) {
|
||||
console.warn("⚠️ One Tap skipped:", notification.getSkippedReason());
|
||||
} else {
|
||||
console.log("✅ One Tap displayed");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function handleCredentialResponse(response) {
|
||||
console.log("=== 🎉 Google Credential Response ===");
|
||||
|
||||
try {
|
||||
if (!response.credential) {
|
||||
throw new Error("No credential in response");
|
||||
}
|
||||
|
||||
const tokenParts = response.credential.split('.');
|
||||
console.log("📝 ID Token parts:", tokenParts.length); // Should be 3 (JWT)
|
||||
console.log("📏 ID Token length:", response.credential.length);
|
||||
|
||||
if (tokenParts.length !== 3) {
|
||||
throw new Error("Invalid JWT format - expected 3 parts (header.payload.signature)");
|
||||
}
|
||||
|
||||
// Dekoduj payload JWT aby wyciągnąć user info
|
||||
const payload = decodeJwtPayload(response.credential);
|
||||
|
||||
const fullName = payload.name || `${payload.given_name || ''} ${payload.family_name || ''}`.trim();
|
||||
const email = payload.email;
|
||||
const avatarUrl = payload.picture || '';
|
||||
|
||||
console.log("👤 User info from JWT:", { fullName, email });
|
||||
console.log("📧 Email verified:", payload.email_verified);
|
||||
|
||||
// Wywołaj Blazor - przekaż ID token JWT (nie access token!)
|
||||
DotNet.invokeMethodAsync('DiunaBI.UI.Shared', 'OnGoogleSignInSuccess',
|
||||
response.credential, // <--- To jest ID token JWT dla backendu
|
||||
fullName,
|
||||
email,
|
||||
avatarUrl)
|
||||
.then(() => {
|
||||
console.log("✅ Successfully sent ID token to Blazor");
|
||||
})
|
||||
.catch(err => {
|
||||
console.error("❌ Error calling Blazor:", err);
|
||||
DotNet.invokeMethodAsync('DiunaBI.UI.Shared', 'OnGoogleSignInError', err.toString());
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("❌ Error processing Google credential:", error);
|
||||
DotNet.invokeMethodAsync('DiunaBI.UI.Shared', 'OnGoogleSignInError', error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
function decodeJwtPayload(token) {
|
||||
try {
|
||||
const base64Url = token.split('.')[1];
|
||||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||||
const jsonPayload = decodeURIComponent(
|
||||
atob(base64)
|
||||
.split('')
|
||||
.map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
|
||||
.join('')
|
||||
);
|
||||
return JSON.parse(jsonPayload);
|
||||
} catch (error) {
|
||||
console.error("Error decoding JWT:", error);
|
||||
throw new Error("Invalid JWT format");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user