From d86e8275638b152dcda36be36574d1af7ad898b5 Mon Sep 17 00:00:00 2001 From: Weiko Date: Mon, 1 Jun 2026 18:08:02 +0200 Subject: [PATCH] fix: return proper FORBIDDEN GraphQL errors from ApiKeyResolver (#21107) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Context CI is broken on main, regression introduced in https://github.com/twentyhq/twenty/pull/21072 Guard-rejected ApiKey mutations returned malformed GraphQL responses. RequireAccessTokenGuard (and SettingsPermissionGuard) throw plain AuthException/PermissionException classes, which are not GraphQLErrors. ApiKeyResolver had no @UseFilters, so these exceptions were never translated, they surfaced as request-level errors with no data key (data: undefined) and a non-FORBIDDEN code, instead of data: null + FORBIDDEN. This broke the `createApiKey › should reject a non-ACCESS token even with API key permission` integration test (expect(res.body.data).toBeNull() received undefined). The sibling generateApiKeyToken test passed only because it lives on AuthResolver, which already declares these filters. ## Fix Add the standard exception filters to ApiKeyResolver, matching the idiom used by other guard-protected resolvers ```ts @UseFilters(AuthGraphqlApiExceptionFilter, PermissionsGraphqlApiExceptionFilter) ``` --- .../src/engine/core-modules/api-key/api-key.resolver.ts | 5 ++++- .../api-key-webhooks.integration-spec.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/twenty-server/src/engine/core-modules/api-key/api-key.resolver.ts b/packages/twenty-server/src/engine/core-modules/api-key/api-key.resolver.ts index 2edc9c105d..617f08ae35 100644 --- a/packages/twenty-server/src/engine/core-modules/api-key/api-key.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/api-key/api-key.resolver.ts @@ -1,4 +1,4 @@ -import { UseGuards } from '@nestjs/common'; +import { UseFilters, UseGuards } from '@nestjs/common'; import { Args, Mutation, Parent, Query, ResolveField } from '@nestjs/graphql'; import { type QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; @@ -7,6 +7,7 @@ import { PermissionFlagType } from 'twenty-shared/constants'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorators/metadata-resolver.decorator'; import { ApiKeyEntity } from 'src/engine/core-modules/api-key/api-key.entity'; +import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter'; import { CreateApiKeyInput } from 'src/engine/core-modules/api-key/dtos/create-api-key.input'; import { GetApiKeyInput } from 'src/engine/core-modules/api-key/dtos/get-api-key.input'; import { RevokeApiKeyInput } from 'src/engine/core-modules/api-key/dtos/revoke-api-key.input'; @@ -17,12 +18,14 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat import { RequireAccessTokenGuard } from 'src/engine/guards/require-access-token.guard'; import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard'; import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; +import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter'; import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto'; import { ApiKeyRoleService } from './services/api-key-role.service'; import { ApiKeyService } from './services/api-key.service'; @MetadataResolver(() => ApiKeyEntity) +@UseFilters(AuthGraphqlApiExceptionFilter, PermissionsGraphqlApiExceptionFilter) @UseGuards( WorkspaceAuthGuard, SettingsPermissionGuard(PermissionFlagType.API_KEYS_AND_WEBHOOKS), diff --git a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/api-key-webhooks.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/api-key-webhooks.integration-spec.ts index 81055c6f6a..e2e3cd854f 100644 --- a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/api-key-webhooks.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/api-key-webhooks.integration-spec.ts @@ -65,7 +65,7 @@ describe('api key and webhooks permissions', () => { const queryData = { query: ` mutation createApiKey { - createApiKey(input: { name: "escalation", expiresAt: "2025-01-01T00:00:00Z" }) { + createApiKey(input: { name: "escalation", expiresAt: "2025-01-01T00:00:00Z", roleId: "20202020-0000-4000-8000-000000000000" }) { id } }