From 9a116b08a4392aad687de7c4b5b48c0ae1a9219f Mon Sep 17 00:00:00 2001 From: Weiko Date: Thu, 2 May 2024 12:54:01 +0200 Subject: [PATCH] User workspace middleware throws 401 if token is invalid (#5245) ## Context Currently, this middleware validates the token and stores the user, workspace and cacheversion in the request object. It only does so when a token is provided and ignores the middleware logic if not. If the token is invalid or expired, the exception is swallowed. This PR removes the try/catch and adds an allowlist to skip the token validation for operations executed while not signed-in. I don't know a better way to do that with Nestjs. We can't easily add the middleware per resolver without refactoring the flexible schema engine so I'm doing it the other way around. Fixes https://github.com/twentyhq/twenty/issues/5224 --- .../middlewares/user-workspace.middleware.ts | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/packages/twenty-server/src/engine/middlewares/user-workspace.middleware.ts b/packages/twenty-server/src/engine/middlewares/user-workspace.middleware.ts index a1ebe7a92..a45c6f6fc 100644 --- a/packages/twenty-server/src/engine/middlewares/user-workspace.middleware.ts +++ b/packages/twenty-server/src/engine/middlewares/user-workspace.middleware.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger, NestMiddleware } from '@nestjs/common'; +import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; @@ -7,28 +7,42 @@ import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/worksp @Injectable() export class UserWorkspaceMiddleware implements NestMiddleware { - private readonly logger = new Logger(UserWorkspaceMiddleware.name); - constructor( private readonly tokenService: TokenService, private readonly workspaceCacheVersionService: WorkspaceCacheVersionService, ) {} async use(req: Request, res: Response, next: NextFunction) { - if (this.tokenService.isTokenPresent(req)) { - try { - const data = await this.tokenService.validateToken(req); - const cacheVersion = await this.workspaceCacheVersionService.getVersion( - data.workspace.id, - ); + const body = req.body; + const excludedOperations = [ + 'GetClientConfig', + 'GetCurrentUser', + 'GetWorkspaceFromInviteHash', + 'Track', + 'CheckUserExists', + 'Challenge', + 'Verify', + 'SignUp', + 'RenewToken', + ]; - req.user = data.user; - req.workspace = data.workspace; - req.cacheVersion = cacheVersion; - } catch (error) { - this.logger.error('Error while validating token in middleware.', error); - } + if ( + body && + body.operationName && + excludedOperations.includes(body.operationName) + ) { + return next(); } + + const data = await this.tokenService.validateToken(req); + const cacheVersion = await this.workspaceCacheVersionService.getVersion( + data.workspace.id, + ); + + req.user = data.user; + req.workspace = data.workspace; + req.cacheVersion = cacheVersion; + next(); } }