From e72a907baaf15b57551341f959b671752e7b28f3 Mon Sep 17 00:00:00 2001 From: martmull Date: Mon, 11 May 2026 15:24:24 +0200 Subject: [PATCH] Stop rejecting application token on calendar and message events requests (#20440) fixes https://github.com/twentyhq/twenty/issues/20423 by authorizing application token to perform calendarEvents and message queries --- .../repository/permissions.utils.ts | 1 + ...alendar-event-find-many.post-query.hook.ts | 19 +++++++++---------- ...calendar-event-find-one.post-query.hook.ts | 19 +++++++++---------- .../message-find-many.post-query.hook.ts | 19 +++++++++---------- .../message-find-one.post-query.hook.ts | 17 +++++++---------- 5 files changed, 35 insertions(+), 40 deletions(-) diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/permissions.utils.ts b/packages/twenty-server/src/engine/twenty-orm/repository/permissions.utils.ts index 36da3fd422..6458d186df 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/permissions.utils.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/permissions.utils.ts @@ -118,6 +118,7 @@ export const validateOperationIsPermittedOrThrow = ({ objectMetadata.universalIdentifier === WORKSPACE_MEMBER_OBJECT_UNIVERSAL_IDENTIFIER; + // TODO: this should be improved, we may have more complex permission configuration for is system objects if (objectMetadataIsSystem && !isWorkspaceMemberObject) { return; } diff --git a/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-many.post-query.hook.ts b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-many.post-query.hook.ts index 75560473b3..334d99f8df 100644 --- a/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-many.post-query.hook.ts +++ b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-many.post-query.hook.ts @@ -5,9 +5,10 @@ import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-r import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard'; import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { ForbiddenError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; import { ApplyCalendarEventsVisibilityRestrictionsService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/apply-calendar-events-visibility-restrictions.service'; import { type CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; +import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard'; +import { isApplicationAuthContext } from 'src/engine/core-modules/auth/guards/is-application-auth-context.guard'; @WorkspaceQueryHook({ key: `calendarEvent.findMany`, @@ -28,17 +29,15 @@ export class CalendarEventFindManyPostQueryHook const isUserContext = isUserAuthContext(authContext); const userId = isUserContext ? authContext.user.id : undefined; - const isTwentyStandardApplication = - authContext.type === 'application' && - authContext.application.universalIdentifier === - TWENTY_STANDARD_APPLICATION.universalIdentifier; - + // TODO: this check should be removed if ( - !isUserContext && - authContext.type !== 'apiKey' && - !isTwentyStandardApplication + !isUserAuthContext(authContext) && + !isApiKeyAuthContext(authContext) && + !isApplicationAuthContext(authContext) ) { - throw new ForbiddenError('Authentication is required'); + throw new ForbiddenError( + 'Authentication error, auth context should be user, apiKey or application', + ); } const workspace = authContext.workspace; diff --git a/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-one.post-query.hook.ts b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-one.post-query.hook.ts index 1f7ccd7777..432adc2676 100644 --- a/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-one.post-query.hook.ts +++ b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/calendar-event-find-one.post-query.hook.ts @@ -5,9 +5,10 @@ import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-r import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard'; import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { ForbiddenError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; import { ApplyCalendarEventsVisibilityRestrictionsService } from 'src/modules/calendar/common/query-hooks/calendar-event/services/apply-calendar-events-visibility-restrictions.service'; import { type CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; +import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard'; +import { isApplicationAuthContext } from 'src/engine/core-modules/auth/guards/is-application-auth-context.guard'; @WorkspaceQueryHook({ key: `calendarEvent.findOne`, @@ -28,17 +29,15 @@ export class CalendarEventFindOnePostQueryHook const isUserContext = isUserAuthContext(authContext); const userId = isUserContext ? authContext.user.id : undefined; - const isTwentyStandardApplication = - authContext.type === 'application' && - authContext.application.universalIdentifier === - TWENTY_STANDARD_APPLICATION.universalIdentifier; - + // TODO: this check should be removed if ( - !isUserContext && - authContext.type !== 'apiKey' && - !isTwentyStandardApplication + !isUserAuthContext(authContext) && + !isApiKeyAuthContext(authContext) && + !isApplicationAuthContext(authContext) ) { - throw new ForbiddenError('Authentication is required'); + throw new ForbiddenError( + 'Authentication error, auth context should be user, apiKey or application', + ); } const workspace = authContext.workspace; diff --git a/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-many.post-query.hook.ts b/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-many.post-query.hook.ts index 25c5a93f4c..656d43beb5 100644 --- a/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-many.post-query.hook.ts +++ b/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-many.post-query.hook.ts @@ -5,9 +5,10 @@ import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-r import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard'; import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { ForbiddenError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; import { ApplyMessagesVisibilityRestrictionsService } from 'src/modules/messaging/common/query-hooks/message/apply-messages-visibility-restrictions.service'; import { type MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; +import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard'; +import { isApplicationAuthContext } from 'src/engine/core-modules/auth/guards/is-application-auth-context.guard'; @WorkspaceQueryHook({ key: `message.findMany`, @@ -25,17 +26,15 @@ export class MessageFindManyPostQueryHook _objectName: string, payload: MessageWorkspaceEntity[], ): Promise { - const isTwentyStandardApplication = - authContext.type === 'application' && - authContext.application.universalIdentifier === - TWENTY_STANDARD_APPLICATION.universalIdentifier; - + // TODO: this check should be removed if ( - authContext.type !== 'user' && - authContext.type !== 'apiKey' && - !isTwentyStandardApplication + !isUserAuthContext(authContext) && + !isApiKeyAuthContext(authContext) && + !isApplicationAuthContext(authContext) ) { - throw new ForbiddenError('Authentication is required'); + throw new ForbiddenError( + 'Authentication error, auth context should be user, apiKey or application', + ); } const workspace = authContext.workspace; diff --git a/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-one.post-query.hook.ts b/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-one.post-query.hook.ts index cd7e53406d..a24e4fe326 100644 --- a/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-one.post-query.hook.ts +++ b/packages/twenty-server/src/modules/messaging/common/query-hooks/message/message-find-one.post-query.hook.ts @@ -2,14 +2,13 @@ import { type WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/work import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; -import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard'; -import { isApplicationAuthContext } from 'src/engine/core-modules/auth/guards/is-application-auth-context.guard'; import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard'; import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { ForbiddenError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; import { ApplyMessagesVisibilityRestrictionsService } from 'src/modules/messaging/common/query-hooks/message/apply-messages-visibility-restrictions.service'; import { type MessageWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message.workspace-entity'; +import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard'; +import { isApplicationAuthContext } from 'src/engine/core-modules/auth/guards/is-application-auth-context.guard'; @WorkspaceQueryHook({ key: `message.findOne`, @@ -27,17 +26,15 @@ export class MessageFindOnePostQueryHook _objectName: string, payload: MessageWorkspaceEntity[], ): Promise { - const isTwentyStandardApplication = - isApplicationAuthContext(authContext) && - authContext.application.universalIdentifier === - TWENTY_STANDARD_APPLICATION.universalIdentifier; - + // TODO: this check should be removed if ( !isUserAuthContext(authContext) && !isApiKeyAuthContext(authContext) && - !isTwentyStandardApplication + !isApplicationAuthContext(authContext) ) { - throw new ForbiddenError('Authentication is required'); + throw new ForbiddenError( + 'Authentication error, auth context should be user, apiKey or application', + ); } const workspace = authContext.workspace;