From ff11ad87a7e0d14298ccad0f0f936761d5544287 Mon Sep 17 00:00:00 2001 From: Tejabudumuru3 Date: Sat, 1 Aug 2026 19:30:23 +0530 Subject: [PATCH] decouples the google auth from sheet service class and fixed side effects --- .../src/services/token-refresh.service.ts | 22 ++++----- .../workflows/[id]/components/ConfigModal.tsx | 46 ++++++++--------- .../nodes/src/common/google-oauth-service.ts | 49 ++++++++++++++++++- .../google-sheets/google-sheets.executor.ts | 6 +-- .../google-sheets/google-sheets.service.ts | 30 ------------ 5 files changed, 81 insertions(+), 72 deletions(-) diff --git a/apps/http-backend/src/services/token-refresh.service.ts b/apps/http-backend/src/services/token-refresh.service.ts index c3ccc4b..5bfc5f5 100644 --- a/apps/http-backend/src/services/token-refresh.service.ts +++ b/apps/http-backend/src/services/token-refresh.service.ts @@ -7,6 +7,7 @@ interface OAuthTokens { token_type: string; expiry_date: number; scope?: string; + email?: string } interface RefreshResult { @@ -35,24 +36,21 @@ class TokenRefreshService { */ private async refreshToken(credentialId: string, tokens: OAuthTokens): Promise { try { - // Use your existing GoogleSheetsService to refresh the token - const sheetService = new GoogleSheetsService({ - access_token: tokens.access_token, - refresh_token: tokens.refresh_token, - token_type: tokens.token_type, - expiry_date: tokens.expiry_date - }); // Use your existing refreshAccessToken method - const newTokens = await sheetService.refreshAccessToken(); + const newTokens = await this.oauthService.refreshAccessToken(tokens.refresh_token); - // Use your existing updateCredentials method from GoogleOAuthService - await this.oauthService.updateCredentials(credentialId, { + const updatedTokens = { access_token: newTokens.access_token, refresh_token: newTokens.refresh_token || tokens.refresh_token, token_type: newTokens.token_type, - expiry_date: newTokens.expiry_date - }); + expiry_date: newTokens.expiry_date, + scope: newTokens.scope || tokens.scope, + email: newTokens.email || tokens.email + }; + + // Use your existing updateCredentials method from GoogleOAuthService + await this.oauthService.updateCredentials(credentialId, updatedTokens); console.log(`✅ Token refreshed for credential: ${credentialId}`); return { credentialId, success: true }; diff --git a/apps/web/app/workflows/[id]/components/ConfigModal.tsx b/apps/web/app/workflows/[id]/components/ConfigModal.tsx index e8ce223..e18eead 100644 --- a/apps/web/app/workflows/[id]/components/ConfigModal.tsx +++ b/apps/web/app/workflows/[id]/components/ConfigModal.tsx @@ -459,7 +459,7 @@ export default function ConfigModal({ key={cred.id} className="px-2.5 py-1 bg-emerald-500/15 text-emerald-400 text-xs rounded-full border border-emerald-500/20 font-medium" > - {cred.email || cred.name} + {cred.config?.email || cred.name} ))} @@ -674,28 +674,28 @@ export default function ConfigModal({ /> ); - return ( -
- - setActiveField(field.name)} - placeholder={field.placeholder} - onChange={(e) => { - const newConfig = { ...config, [field.name]: e.target.value }; - setConfig(newConfig) - dispatchConfig(newConfig) - } - } - className="w-full p-2.5 border border-[#1e293b] bg-[#0a0e17] text-gray-200 rounded-lg focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500/50 transition-all outline-none text-sm placeholder-gray-600" - required={field.required} - /> -
- ); + // return ( + //
+ // + // setActiveField(field.name)} + // placeholder={field.placeholder} + // onChange={(e) => { + // const newConfig = { ...config, [field.name]: e.target.value }; + // setConfig(newConfig) + // dispatchConfig(newConfig) + // } + // } + // className="w-full p-2.5 border border-[#1e293b] bg-[#0a0e17] text-gray-200 rounded-lg focus:ring-2 focus:ring-indigo-500/50 focus:border-indigo-500/50 transition-all outline-none text-sm placeholder-gray-600" + // required={field.required} + // /> + //
+ // ); }; return ( diff --git a/packages/nodes/src/common/google-oauth-service.ts b/packages/nodes/src/common/google-oauth-service.ts index 420f610..f34915c 100644 --- a/packages/nodes/src/common/google-oauth-service.ts +++ b/packages/nodes/src/common/google-oauth-service.ts @@ -100,6 +100,39 @@ class GoogleOAuthService { } } + isTokenExpired(expiry_date: number): boolean { + if (!expiry_date) return false; + + return Date.now() >= expiry_date - (5 * 60 * 1000); + } + + async refreshAccessToken(refresh_token: string): Promise { + try { + await this.oauth2Client.setCredentials({ refresh_token: refresh_token }) + const { credentials } = await this.oauth2Client.refreshAccessToken(); + + // IMPORTANT: Only include refresh_token if Google returns a new one + // Google doesn't always return a new refresh_token on every refresh + const result: OAuthTokens = { + access_token: credentials.access_token || '', + refresh_token: '', // Will be set below if present + token_type: credentials.token_type || '', + expiry_date: credentials.expiry_date || 0, + scope: credentials.scope || '' + }; + + // Only include refresh_token if Google actually returned one + if (credentials.refresh_token) { + result.refresh_token = credentials.refresh_token; + } + + return result; + } + catch (error) { + throw new Error(`Failed to refresh token: ${error}`) + } + } + async getCredentials( userId: string, credentialId: string, @@ -117,11 +150,23 @@ class GoogleOAuthService { id: "desc", }, }); - console.log("credentails from oauth service: ", credentials); if (!credentials) return null; + let tokens = credentials?.config as unknown as OAuthTokens + + if (this.isTokenExpired(tokens.expiry_date) && tokens.refresh_token) { + const newTokens = await this.refreshAccessToken(tokens.refresh_token) + if (!newTokens.scope) newTokens.scope = tokens.scope + if (!newTokens.email) newTokens.email = tokens.email + if (!newTokens.refresh_token) newTokens.refresh_token = tokens.refresh_token + + await this.updateCredentials(credentialId, newTokens) + + tokens = { ...tokens, ...newTokens } + } + return { id: credentials.id, - tokens: credentials.config as unknown as OAuthTokens, + tokens: tokens as OAuthTokens, }; } catch (err) { throw new Error( diff --git a/packages/nodes/src/google-sheets/google-sheets.executor.ts b/packages/nodes/src/google-sheets/google-sheets.executor.ts index b561981..85ece00 100644 --- a/packages/nodes/src/google-sheets/google-sheets.executor.ts +++ b/packages/nodes/src/google-sheets/google-sheets.executor.ts @@ -135,10 +135,6 @@ class GoogleSheetsNodeExecutor { }; } - if (sheetService.isTokenExpired()) { - const newTokens = await sheetService.refreshAccessToken(); - await this.oauthService.updateCredentials(credentialId, newTokens) - } const operation = context.config.operation; console.log("operation from sheet executor: ", operation) @@ -444,7 +440,7 @@ class GoogleSheetsNodeExecutor { async executeClearRows(sheetService: GoogleSheetsService, context: NodeExecutionContext): Promise { try { const spreadsheetId = context.config.spreadsheetId; - const range = (!context.config.clearEntireTable && context.config.range) ? context.config.range : (context.config.includeHeaderRow ? `${context.config.sheetName}!A1:Z` : `${context.config.sheetName}!A2:Z`); + const range = (!context.config.clearEntireTable && context.config.range) ? `${context.config.sheetName}!${context.config.range}` : (context.config.includeHeaderRow ? `${context.config.sheetName}!A1:Z` : `${context.config.sheetName}!A2:Z`); const response = await sheetService.clearRows({ spreadsheetId: spreadsheetId, diff --git a/packages/nodes/src/google-sheets/google-sheets.service.ts b/packages/nodes/src/google-sheets/google-sheets.service.ts index 2125071..5eb7727 100644 --- a/packages/nodes/src/google-sheets/google-sheets.service.ts +++ b/packages/nodes/src/google-sheets/google-sheets.service.ts @@ -162,37 +162,7 @@ class GoogleSheetsService { } } - isTokenExpired(): boolean { - const credentials = this.auth.credentials; - if (!credentials.expiry_date) return false; - return Date.now() >= credentials.expiry_date - (5 * 60 * 1000); - } - - async refreshAccessToken(): Promise { - try { - const { credentials } = await this.auth.refreshAccessToken(); - - // IMPORTANT: Only include refresh_token if Google returns a new one - // Google doesn't always return a new refresh_token on every refresh - const result: GoogleSheetsCredentials = { - access_token: credentials.access_token || '', - refresh_token: '', // Will be set below if present - token_type: credentials.token_type || '', - expiry_date: credentials.expiry_date || 0 - }; - - // Only include refresh_token if Google actually returned one - if (credentials.refresh_token) { - result.refresh_token = credentials.refresh_token; - } - - return result; - } - catch (error) { - throw new Error(`Failed to refresh token: ${error}`) - } - } } export { GoogleSheetsService }