120 lines
3.5 KiB
TypeScript
120 lines
3.5 KiB
TypeScript
import { redirect } from '@sveltejs/kit';
|
|
import type { RequestHandler } from './$types';
|
|
import { googleAuthServer } from '$lib/google/server.ts';
|
|
|
|
export const GET: RequestHandler = async ({ url }) => {
|
|
try {
|
|
const code = url.searchParams.get('code');
|
|
const error = url.searchParams.get('error');
|
|
|
|
if (error) {
|
|
console.error('Google OAuth error:', error);
|
|
throw redirect(302, '/private/events?error=google_auth_denied');
|
|
}
|
|
|
|
if (!code) {
|
|
throw redirect(302, '/private/events?error=missing_auth_code');
|
|
}
|
|
|
|
// Exchange code for tokens
|
|
const oauth = googleAuthServer.getOAuthClient();
|
|
const { tokens } = await oauth.getToken(code);
|
|
|
|
if (!tokens.refresh_token || !tokens.access_token) {
|
|
throw redirect(302, '/private/events?error=incomplete_tokens');
|
|
}
|
|
|
|
// Get user info to retrieve email
|
|
let userEmail = '';
|
|
try {
|
|
oauth.setCredentials(tokens);
|
|
const { google } = await import('googleapis');
|
|
const oauth2 = google.oauth2({ version: 'v2', auth: oauth });
|
|
const userInfo = await oauth2.userinfo.get();
|
|
userEmail = userInfo.data.email ?? '';
|
|
} catch (emailError) {
|
|
console.error('Error fetching user email:', emailError);
|
|
// Continue without email - it's not critical for the auth flow
|
|
}
|
|
|
|
// Create a success page with tokens that closes the popup and communicates with parent
|
|
const html = `
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Google Authentication Success</title>
|
|
<style>
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100vh;
|
|
margin: 0;
|
|
background: #f9fafb;
|
|
}
|
|
.container {
|
|
text-align: center;
|
|
padding: 2rem;
|
|
background: white;
|
|
border-radius: 8px;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
}
|
|
.success {
|
|
color: #059669;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.loading {
|
|
color: #6b7280;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="success">✓ Authentication successful!</div>
|
|
<div class="loading">Closing window...</div>
|
|
</div>
|
|
<script>
|
|
(function() {
|
|
try {
|
|
// Store tokens in localStorage (same origin)
|
|
localStorage.setItem('google_access_token', '${tokens.access_token}');
|
|
localStorage.setItem('google_refresh_token', '${tokens.refresh_token}');
|
|
${userEmail ? `localStorage.setItem('google_user_email', '${userEmail}');` : ''}
|
|
// Set timestamp that the main application will detect
|
|
localStorage.setItem('google_auth_timestamp', Date.now().toString());
|
|
|
|
// Update UI to show success
|
|
document.querySelector('.loading').textContent = 'Authentication complete! This window will close automatically.';
|
|
|
|
// Close window after a short delay
|
|
setTimeout(() => {
|
|
try {
|
|
window.close();
|
|
} catch (e) {
|
|
// If we can't close automatically, update message
|
|
document.querySelector('.loading').textContent = 'Authentication complete! You can close this window now.';
|
|
}
|
|
}, 1500);
|
|
} catch (error) {
|
|
console.error('Error in auth callback:', error);
|
|
// Update UI to show error
|
|
document.querySelector('.success').textContent = '✗ Authentication error';
|
|
document.querySelector('.loading').textContent = 'Please close this window and try again.';
|
|
}
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>`;
|
|
|
|
return new Response(html, {
|
|
headers: {
|
|
'Content-Type': 'text/html'
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('Error handling Google OAuth callback:', error);
|
|
throw redirect(302, '/private/events?error=google_auth_failed');
|
|
}
|
|
};
|