diff --git a/packages/twenty-server/src/engine/core-modules/auth/auth.exception.ts b/packages/twenty-server/src/engine/core-modules/auth/auth.exception.ts index c245db971..6195fd37d 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/auth.exception.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/auth.exception.ts @@ -12,6 +12,7 @@ export enum AuthExceptionCode { CLIENT_NOT_FOUND = 'CLIENT_NOT_FOUND', INVALID_INPUT = 'INVALID_INPUT', FORBIDDEN_EXCEPTION = 'FORBIDDEN_EXCEPTION', + UNAUTHENTICATED = 'UNAUTHENTICATED', INVALID_DATA = 'INVALID_DATA', INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR', } diff --git a/packages/twenty-server/src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter.ts b/packages/twenty-server/src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter.ts index ebabba88f..c33c724f0 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter.ts @@ -1,10 +1,11 @@ -import { Catch } from '@nestjs/common'; +import { Catch, ExceptionFilter } from '@nestjs/common'; import { AuthException, AuthExceptionCode, } from 'src/engine/core-modules/auth/auth.exception'; import { + AuthenticationError, ForbiddenError, InternalServerError, NotFoundError, @@ -12,7 +13,7 @@ import { } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; @Catch(AuthException) -export class AuthGraphqlApiExceptionFilter { +export class AuthGraphqlApiExceptionFilter implements ExceptionFilter { catch(exception: AuthException) { switch (exception.code) { case AuthExceptionCode.USER_NOT_FOUND: @@ -22,6 +23,8 @@ export class AuthGraphqlApiExceptionFilter { throw new UserInputError(exception.message); case AuthExceptionCode.FORBIDDEN_EXCEPTION: throw new ForbiddenError(exception.message); + case AuthExceptionCode.UNAUTHENTICATED: + throw new AuthenticationError(exception.message); case AuthExceptionCode.INVALID_DATA: case AuthExceptionCode.INTERNAL_SERVER_ERROR: default: diff --git a/packages/twenty-server/src/engine/core-modules/auth/services/token.service.ts b/packages/twenty-server/src/engine/core-modules/auth/services/token.service.ts index 9a45a3a37..da571fbe5 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/services/token.service.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/services/token.service.ts @@ -564,12 +564,12 @@ export class TokenService { if (error instanceof TokenExpiredError) { throw new AuthException( 'Token has expired.', - AuthExceptionCode.FORBIDDEN_EXCEPTION, + AuthExceptionCode.UNAUTHENTICATED, ); } else if (error instanceof JsonWebTokenError) { throw new AuthException( 'Token invalid.', - AuthExceptionCode.FORBIDDEN_EXCEPTION, + AuthExceptionCode.UNAUTHENTICATED, ); } else { throw new AuthException( diff --git a/packages/twenty-server/src/engine/middlewares/graphql-hydrate-request-from-token.middleware.ts b/packages/twenty-server/src/engine/middlewares/graphql-hydrate-request-from-token.middleware.ts index 4a402cb27..a756b8cef 100644 --- a/packages/twenty-server/src/engine/middlewares/graphql-hydrate-request-from-token.middleware.ts +++ b/packages/twenty-server/src/engine/middlewares/graphql-hydrate-request-from-token.middleware.ts @@ -1,13 +1,32 @@ import { Injectable, NestMiddleware } from '@nestjs/common'; -import { Request, Response, NextFunction } from 'express'; +import { NextFunction, Request, Response } from 'express'; +import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter'; import { TokenService } from 'src/engine/core-modules/auth/services/token.service'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; import { ExceptionHandlerService } from 'src/engine/integrations/exception-handler/exception-handler.service'; import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; import { handleExceptionAndConvertToGraphQLError } from 'src/engine/utils/global-exception-handler.util'; +class GraphqlTokenValidationProxy { + private tokenService: TokenService; + + constructor(tokenService: TokenService) { + this.tokenService = tokenService; + } + + async validateToken(req: Request) { + try { + return await this.tokenService.validateToken(req); + } catch (error) { + const authGraphqlApiExceptionFilter = new AuthGraphqlApiExceptionFilter(); + + throw authGraphqlApiExceptionFilter.catch(error); + } + } +} + @Injectable() export class GraphQLHydrateRequestFromTokenMiddleware implements NestMiddleware @@ -48,7 +67,11 @@ export class GraphQLHydrateRequestFromTokenMiddleware let data: AuthContext; try { - data = await this.tokenService.validateToken(req); + const graphqlTokenValidationProxy = new GraphqlTokenValidationProxy( + this.tokenService, + ); + + data = await graphqlTokenValidationProxy.validateToken(req); const cacheVersion = await this.workspaceCacheVersionService.getVersion( data.workspace.id, );