Handle token refresh for supabase
This commit is contained in:
@@ -1,11 +1,90 @@
|
||||
import { readSettings } from "../main/settings";
|
||||
import { withLock } from "../ipc/utils/lock_utils";
|
||||
import { readSettings, writeSettings } from "../main/settings";
|
||||
import { SupabaseManagementAPI } from "supabase-management-js";
|
||||
|
||||
/**
|
||||
* Checks if the Supabase access token is expired or about to expire
|
||||
* Returns true if token needs to be refreshed
|
||||
*/
|
||||
function isTokenExpired(expiresIn?: number): boolean {
|
||||
if (!expiresIn) return true;
|
||||
|
||||
// Get when the token was saved (expiresIn is stored at the time of token receipt)
|
||||
const settings = readSettings();
|
||||
const tokenTimestamp = settings.supabase?.tokenTimestamp || 0;
|
||||
const currentTime = Math.floor(Date.now() / 1000);
|
||||
|
||||
// Check if the token is expired or about to expire (within 5 minutes)
|
||||
return currentTime >= tokenTimestamp + expiresIn - 300;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the Supabase access token using the refresh token
|
||||
* Updates settings with new tokens and expiration time
|
||||
*/
|
||||
export async function refreshSupabaseToken(): Promise<void> {
|
||||
const settings = readSettings();
|
||||
const refreshToken = settings.supabase?.refreshToken?.value;
|
||||
|
||||
if (!isTokenExpired(settings.supabase?.expiresIn)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!refreshToken) {
|
||||
throw new Error(
|
||||
"Supabase refresh token not found. Please authenticate first."
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// Make request to Supabase refresh endpoint
|
||||
const response = await fetch(
|
||||
"https://supabase-oauth.dyad.sh/api/connect-supabase/refresh",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ refreshToken }),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Token refresh failed: ${response.statusText}`);
|
||||
}
|
||||
|
||||
const {
|
||||
accessToken,
|
||||
refreshToken: newRefreshToken,
|
||||
expiresIn,
|
||||
} = await response.json();
|
||||
|
||||
// Update settings with new tokens
|
||||
writeSettings({
|
||||
supabase: {
|
||||
accessToken: {
|
||||
value: accessToken,
|
||||
},
|
||||
refreshToken: {
|
||||
value: newRefreshToken,
|
||||
},
|
||||
expiresIn,
|
||||
tokenTimestamp: Math.floor(Date.now() / 1000), // Store current timestamp
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error refreshing Supabase token:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to get the Supabase Management API client
|
||||
export async function getSupabaseClient(): Promise<SupabaseManagementAPI> {
|
||||
const settings = readSettings();
|
||||
|
||||
// Check if Supabase token exists in settings
|
||||
const supabaseAccessToken = settings.supabase?.accessToken?.value;
|
||||
const expiresIn = settings.supabase?.expiresIn;
|
||||
|
||||
if (!supabaseAccessToken) {
|
||||
throw new Error(
|
||||
@@ -13,6 +92,22 @@ export async function getSupabaseClient(): Promise<SupabaseManagementAPI> {
|
||||
);
|
||||
}
|
||||
|
||||
// Check if token needs refreshing
|
||||
if (isTokenExpired(expiresIn)) {
|
||||
await withLock("refresh-supabase-token", refreshSupabaseToken);
|
||||
// Get updated settings after refresh
|
||||
const updatedSettings = readSettings();
|
||||
const newAccessToken = updatedSettings.supabase?.accessToken?.value;
|
||||
|
||||
if (!newAccessToken) {
|
||||
throw new Error("Failed to refresh Supabase access token");
|
||||
}
|
||||
|
||||
return new SupabaseManagementAPI({
|
||||
accessToken: newAccessToken,
|
||||
});
|
||||
}
|
||||
|
||||
return new SupabaseManagementAPI({
|
||||
accessToken: supabaseAccessToken,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user