Implement token caching to avoid unnecessary refresh token calls
- Add expires_at timestamp to OAuth config - Cache access_token in database to reuse across requests - Only refresh token when it expires (after 1 hour) - Use 60-second buffer to avoid using almost-expired tokens - Auto-update cached token after refresh - This fixes the invalid_grant error from excessive refresh calls
This commit is contained in:
@@ -10,6 +10,8 @@ interface GoogleOAuthConfig {
|
||||
client_id: string;
|
||||
client_secret: string;
|
||||
refresh_token: string;
|
||||
access_token?: string;
|
||||
expires_at?: number; // Timestamp when access_token expires
|
||||
}
|
||||
|
||||
interface CreateMeetRequest {
|
||||
@@ -24,22 +26,36 @@ interface CreateMeetRequest {
|
||||
}
|
||||
|
||||
// Function to get access token from refresh token (OAuth2)
|
||||
async function getGoogleAccessToken(oauthConfig: GoogleOAuthConfig): Promise<string> {
|
||||
async function getGoogleAccessToken(oauthConfig: GoogleOAuthConfig): Promise<{ access_token: string; expires_in: number }> {
|
||||
try {
|
||||
const response = await fetch("https://oauth2.googleapis.com/token", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: new URLSearchParams({
|
||||
console.log("Attempting to exchange refresh token for access token...");
|
||||
console.log("Client ID:", oauthConfig.client_id);
|
||||
|
||||
const tokenRequest = {
|
||||
client_id: oauthConfig.client_id,
|
||||
client_secret: oauthConfig.client_secret,
|
||||
refresh_token: oauthConfig.refresh_token,
|
||||
grant_type: "refresh_token",
|
||||
}),
|
||||
};
|
||||
|
||||
console.log("Token request payload:", JSON.stringify({
|
||||
...tokenRequest,
|
||||
client_secret: "***REDACTED***",
|
||||
refresh_token: tokenRequest.refresh_token.substring(0, 20) + "..."
|
||||
}));
|
||||
|
||||
const response = await fetch("https://oauth2.googleapis.com/token", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: new URLSearchParams(tokenRequest),
|
||||
});
|
||||
|
||||
const responseText = await response.text();
|
||||
console.log("Token response status:", response.status);
|
||||
console.log("Token response body:", responseText);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Token exchange failed: ${errorText}`);
|
||||
throw new Error(`Token exchange failed: ${responseText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
@@ -48,7 +64,11 @@ async function getGoogleAccessToken(oauthConfig: GoogleOAuthConfig): Promise<str
|
||||
throw new Error("No access token in response");
|
||||
}
|
||||
|
||||
return data.access_token;
|
||||
console.log("Successfully obtained access token");
|
||||
return {
|
||||
access_token: data.access_token,
|
||||
expires_in: data.expires_in || 3600
|
||||
};
|
||||
} catch (error: any) {
|
||||
console.error("Error getting Google access token:", error);
|
||||
throw error;
|
||||
@@ -119,8 +139,36 @@ serve(async (req: Request): Promise<Response> => {
|
||||
);
|
||||
}
|
||||
|
||||
// Get access token using OAuth2 refresh token
|
||||
const accessToken = await getGoogleAccessToken(oauthConfig);
|
||||
// Check if we have a valid cached access_token
|
||||
let accessToken: string;
|
||||
const now = Math.floor(Date.now() / 1000); // Current time in seconds
|
||||
|
||||
if (oauthConfig.access_token && oauthConfig.expires_at && oauthConfig.expires_at > now + 60) {
|
||||
// Token is still valid (with 60 second buffer)
|
||||
console.log("Using cached access_token (expires at:", new Date(oauthConfig.expires_at * 1000).toISOString(), ")");
|
||||
accessToken = oauthConfig.access_token;
|
||||
} else {
|
||||
// Need to refresh the token
|
||||
console.log("Access token expired or missing, refreshing...");
|
||||
const tokenData = await getGoogleAccessToken(oauthConfig);
|
||||
accessToken = tokenData.access_token;
|
||||
|
||||
// Update the cached token in database with new expiry
|
||||
const newExpiresAt = now + tokenData.expires_in;
|
||||
const updatedConfig = {
|
||||
...oauthConfig,
|
||||
access_token: accessToken,
|
||||
expires_at: newExpiresAt
|
||||
};
|
||||
|
||||
// Save updated config back to database
|
||||
await supabase
|
||||
.from("platform_settings")
|
||||
.update({ google_oauth_config: JSON.stringify(updatedConfig) })
|
||||
.eq("id", settings.id);
|
||||
|
||||
console.log("Updated cached access_token in database");
|
||||
}
|
||||
console.log("Got access token");
|
||||
|
||||
// Build event data
|
||||
|
||||
Reference in New Issue
Block a user