Compare commits
3 Commits
eb0276e475
...
cdc8b89916
| Author | SHA1 | Date | |
|---|---|---|---|
| cdc8b89916 | |||
| 9dd79514f5 | |||
|
|
cd37d8da0f |
@@ -21,8 +21,8 @@
|
|||||||
let authState = $state(createGoogleAuthState());
|
let authState = $state(createGoogleAuthState());
|
||||||
let authManager = new GoogleAuthManager(authState);
|
let authManager = new GoogleAuthManager(authState);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(async () => {
|
||||||
authManager.checkConnection();
|
await authManager.checkConnection();
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleConnect() {
|
async function handleConnect() {
|
||||||
@@ -57,7 +57,14 @@
|
|||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if authState.isConnected}
|
{#if authState.checking}
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="flex items-center gap-2 rounded-full bg-gray-100 px-3 py-1 border border-gray-300 whitespace-nowrap">
|
||||||
|
<div class="w-4 h-4 animate-spin rounded-full border-2 border-current border-t-transparent text-gray-600"></div>
|
||||||
|
<span class="text-sm font-medium text-gray-800">Checking connection...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{:else if authState.isConnected}
|
||||||
<div class="flex flex-wrap items-center gap-3">
|
<div class="flex flex-wrap items-center gap-3">
|
||||||
<div class="flex items-center gap-2 rounded-full bg-green-100 px-3 py-1 border border-green-300 whitespace-nowrap">
|
<div class="flex items-center gap-2 rounded-full bg-green-100 px-3 py-1 border border-green-300 whitespace-nowrap">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-green-600" viewBox="0 0 20 20" fill="currentColor">
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-green-600" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export class GoogleAuthManager {
|
|||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkConnection(): void {
|
async checkConnection(): Promise<void> {
|
||||||
this.state.checking = true;
|
this.state.checking = true;
|
||||||
this.state.error = null;
|
this.state.error = null;
|
||||||
|
|
||||||
@@ -38,12 +38,39 @@ export class GoogleAuthManager {
|
|||||||
const token = localStorage.getItem('google_refresh_token');
|
const token = localStorage.getItem('google_refresh_token');
|
||||||
const email = localStorage.getItem('google_user_email');
|
const email = localStorage.getItem('google_user_email');
|
||||||
|
|
||||||
this.state.isConnected = !!token;
|
if (!token) {
|
||||||
this.state.token = token;
|
this.state.isConnected = false;
|
||||||
this.state.userEmail = email;
|
this.state.token = null;
|
||||||
|
this.state.userEmail = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the token by calling our backend endpoint
|
||||||
|
const response = await fetch('/private/api/google/auth/check', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ refreshToken: token })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
this.state.isConnected = true;
|
||||||
|
this.state.token = token;
|
||||||
|
this.state.userEmail = email;
|
||||||
|
} else {
|
||||||
|
// Token is invalid or expired
|
||||||
|
await this.disconnectGoogle();
|
||||||
|
if (response.status === 401) {
|
||||||
|
this.state.error = 'Google session expired. Please reconnect.';
|
||||||
|
} else {
|
||||||
|
this.state.error = 'Failed to verify connection.';
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error checking connection:', error);
|
console.error('Error checking connection:', error);
|
||||||
this.state.error = 'Failed to check connection status';
|
this.state.error = 'Failed to verify connection status';
|
||||||
|
this.state.isConnected = false;
|
||||||
} finally {
|
} finally {
|
||||||
this.state.checking = false;
|
this.state.checking = false;
|
||||||
}
|
}
|
||||||
|
|||||||
32
src/routes/private/api/google/auth/check/+server.ts
Normal file
32
src/routes/private/api/google/auth/check/+server.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { json } from '@sveltejs/kit';
|
||||||
|
import { getAuthenticatedClient } from '$lib/google/auth/server';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Verify the validity of a Google refresh token
|
||||||
|
* @method POST
|
||||||
|
* @param {Request} request
|
||||||
|
* @returns {Response}
|
||||||
|
*/
|
||||||
|
export async function POST({ request }: { request: Request }): Promise<Response> {
|
||||||
|
try {
|
||||||
|
const { refreshToken } = await request.json();
|
||||||
|
|
||||||
|
if (!refreshToken) {
|
||||||
|
return json({ error: 'Refresh token is required' }, { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an authenticated client. This will attempt to get a new access token,
|
||||||
|
// which effectively validates the refresh token.
|
||||||
|
const oauth2Client = getAuthenticatedClient(refreshToken);
|
||||||
|
|
||||||
|
// Attempt to get a new access token
|
||||||
|
await oauth2Client.getAccessToken();
|
||||||
|
|
||||||
|
// If no error is thrown, the token is valid
|
||||||
|
return json({ success: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to verify Google refresh token:', error);
|
||||||
|
// The token is likely invalid or revoked
|
||||||
|
return json({ error: 'Invalid or expired refresh token' }, { status: 401 });
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user