refactor google refresh token service error handling (#17127)
Refactors to be consistent with Microsoft service Handles scenarios like temporary error which was not handled before Moved `IsGmailNetworkError` from root orchestrator to driver level
This commit is contained in:
+4
-10
@@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { GaxiosError } from 'gaxios';
|
||||
import { google } from 'googleapis';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -10,6 +9,7 @@ import {
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode,
|
||||
} from 'src/modules/connected-account/refresh-tokens-manager/exceptions/connected-account-refresh-tokens.exception';
|
||||
import { type ConnectedAccountTokens } from 'src/modules/connected-account/refresh-tokens-manager/services/connected-account-refresh-tokens.service';
|
||||
import { parseGoogleOAuthError } from 'src/modules/connected-account/refresh-tokens-manager/drivers/google/utils/parse-google-oauth-error.util';
|
||||
|
||||
@Injectable()
|
||||
export class GoogleAPIRefreshAccessTokenService {
|
||||
@@ -39,17 +39,11 @@ export class GoogleAPIRefreshAccessTokenService {
|
||||
refreshToken,
|
||||
};
|
||||
} catch (error) {
|
||||
if (
|
||||
error instanceof GaxiosError &&
|
||||
error.response?.data?.error === 'invalid_grant'
|
||||
) {
|
||||
throw new ConnectedAccountRefreshAccessTokenException(
|
||||
'Error refreshing Google tokens: Invalid refresh token',
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode.INVALID_REFRESH_TOKEN,
|
||||
);
|
||||
if (error instanceof ConnectedAccountRefreshAccessTokenException) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw error;
|
||||
throw parseGoogleOAuthError(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
import { type GaxiosError } from 'gaxios';
|
||||
|
||||
import {
|
||||
ConnectedAccountRefreshAccessTokenException,
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode,
|
||||
} from 'src/modules/connected-account/refresh-tokens-manager/exceptions/connected-account-refresh-tokens.exception';
|
||||
import { isGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-network-error.util';
|
||||
|
||||
export const parseGoogleOAuthError = (
|
||||
error: unknown,
|
||||
): ConnectedAccountRefreshAccessTokenException => {
|
||||
if (isGmailNetworkError(error)) {
|
||||
return new ConnectedAccountRefreshAccessTokenException(
|
||||
`Google refresh token network error: ${error.code} - ${error.message}`,
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode.TEMPORARY_NETWORK_ERROR,
|
||||
);
|
||||
}
|
||||
|
||||
const gaxiosError = error as GaxiosError;
|
||||
|
||||
const googleOAuthError = {
|
||||
code: gaxiosError.response?.status,
|
||||
reason:
|
||||
gaxiosError.response?.data?.error ||
|
||||
gaxiosError.response?.data?.error_description ||
|
||||
'Unknown reason',
|
||||
message:
|
||||
gaxiosError.response?.data?.error_description ||
|
||||
gaxiosError.message ||
|
||||
'Unknown error',
|
||||
};
|
||||
|
||||
switch (googleOAuthError.code) {
|
||||
case 400:
|
||||
if (googleOAuthError.reason === 'invalid_grant') {
|
||||
return new ConnectedAccountRefreshAccessTokenException(
|
||||
googleOAuthError.message,
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode.INVALID_REFRESH_TOKEN,
|
||||
);
|
||||
}
|
||||
|
||||
return new ConnectedAccountRefreshAccessTokenException(
|
||||
googleOAuthError.message,
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode.INVALID_REFRESH_TOKEN,
|
||||
);
|
||||
|
||||
case 401:
|
||||
return new ConnectedAccountRefreshAccessTokenException(
|
||||
googleOAuthError.message,
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode.INVALID_REFRESH_TOKEN,
|
||||
);
|
||||
|
||||
case 403:
|
||||
return new ConnectedAccountRefreshAccessTokenException(
|
||||
googleOAuthError.message,
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode.INVALID_REFRESH_TOKEN,
|
||||
);
|
||||
|
||||
case 429:
|
||||
return new ConnectedAccountRefreshAccessTokenException(
|
||||
googleOAuthError.message,
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode.TEMPORARY_NETWORK_ERROR,
|
||||
);
|
||||
|
||||
case 500:
|
||||
case 502:
|
||||
case 503:
|
||||
case 504:
|
||||
return new ConnectedAccountRefreshAccessTokenException(
|
||||
`${googleOAuthError.code} - ${googleOAuthError.message}`,
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode.TEMPORARY_NETWORK_ERROR,
|
||||
);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return new ConnectedAccountRefreshAccessTokenException(
|
||||
`Google refresh token failed: ${googleOAuthError.message}`,
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode.INVALID_REFRESH_TOKEN,
|
||||
);
|
||||
};
|
||||
+4
-3
@@ -275,9 +275,10 @@ describe('ConnectedAccountRefreshTokensService', () => {
|
||||
lastCredentialsRefreshedAt: new Date(Date.now() - 2 * 60 * 60 * 1000), // 2 hours ago
|
||||
} as ConnectedAccountWorkspaceEntity;
|
||||
|
||||
const networkError = new Error('Network error');
|
||||
|
||||
(networkError as any).code = 'ECONNRESET';
|
||||
const networkError = new ConnectedAccountRefreshAccessTokenException(
|
||||
'Google refresh token network error: ECONNRESET - Network error',
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode.TEMPORARY_NETWORK_ERROR,
|
||||
);
|
||||
|
||||
jest
|
||||
.spyOn(googleAPIRefreshAccessTokenService, 'refreshTokens')
|
||||
|
||||
-8
@@ -12,7 +12,6 @@ import {
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode,
|
||||
} from 'src/modules/connected-account/refresh-tokens-manager/exceptions/connected-account-refresh-tokens.exception';
|
||||
import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
import { isGmailNetworkError } from 'src/modules/messaging/message-import-manager/drivers/gmail/utils/is-gmail-network-error.util';
|
||||
|
||||
export type ConnectedAccountTokens = {
|
||||
accessToken: string;
|
||||
@@ -157,13 +156,6 @@ export class ConnectedAccountRefreshTokensService {
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (isGmailNetworkError(error)) {
|
||||
throw new ConnectedAccountRefreshAccessTokenException(
|
||||
`Error refreshing tokens for connected account ${connectedAccount.id} in workspace ${workspaceId}: ${error.code}`,
|
||||
ConnectedAccountRefreshAccessTokenExceptionCode.TEMPORARY_NETWORK_ERROR,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Error while refreshing tokens on connected account ${connectedAccount.id} in workspace ${workspaceId}`,
|
||||
error,
|
||||
|
||||
Reference in New Issue
Block a user