Skip to content

Commit fc908e9

Browse files
authored
Refactor WorkspaceAuthContext to use discriminated union types (#17491)
## Context The previous WorkspaceAuthContext was a single interface with many optional fields, making it unclear which fields are available in different authentication scenarios. This made the code harder to reason about and required runtime checks scattered throughout the codebase. ## Changes - Introduced a discriminated union type for WorkspaceAuthContext with four specific variants: -> UserWorkspaceAuthContext - for authenticated users -> ApiKeyWorkspaceAuthContext - for API key authentication -> ApplicationWorkspaceAuthContext - for application-based auth -> SystemWorkspaceAuthContext - for system/internal operations - Added type guard functions (isUserAuthContext, isApiKeyAuthContext, etc.) for safe type narrowing - Added builder utilities (buildUserAuthContext, buildApiKeyAuthContext, etc.) to construct each context variant with proper type safety - Refactored WorkspaceAuthContextMiddleware to use the new builders instead of constructing a loosely-typed object - Moved the type definition from twenty-orm/interfaces/ to core-modules/auth/types/ for better organization - Updated all consumers across query runners, tool providers, and modules to use the new type location ## Notes - I had to query User and WorkspaceMember in some parts of tool module that were expecting userWorkspaceId but not the rest of UserWorkspaceAuthContext (that should be required with the new proper type otherwise it would break a lot of logic and mostly permissions with the newly added RLS -> This is what we expect from UserWorkspaceAuthContext and how it's done in the "normal" path in HTTP middleware) - WorkspaceMember is in the cache already but ideally we should move User (And Workspace?) in the cache as well to avoid querying the DB after each request (this is also valid for HTTP middleware when we hydrate the Request object btw)
1 parent 59f7582 commit fc908e9

File tree

63 files changed

+544
-186
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+544
-186
lines changed

packages/twenty-server/src/engine/api/common/common-query-runners/common-base-query-runner.service.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { Inject, Injectable } from '@nestjs/common';
33
import { type PermissionFlagType } from 'twenty-shared/constants';
44
import { isDefined } from 'twenty-shared/utils';
55

6-
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
76
import { QueryResultFieldValue } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/interfaces/query-result-field-value';
87

98
import { DataArgProcessor } from 'src/engine/api/common/common-args-processors/data-arg-processor/data-arg.processor';
@@ -24,14 +23,17 @@ import {
2423
} from 'src/engine/api/common/types/common-query-args.type';
2524
import { CommonQueryResult } from 'src/engine/api/common/types/common-query-result.type';
2625
import { CommonSelectedFieldsResult } from 'src/engine/api/common/types/common-selected-fields-result.type';
27-
import { isWorkspaceAuthContext } from 'src/engine/api/common/utils/is-workspace-auth-context.util';
2826
import { OBJECTS_WITH_SETTINGS_PERMISSIONS_REQUIREMENTS } from 'src/engine/api/graphql/graphql-query-runner/constants/objects-with-settings-permissions-requirements';
2927
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
3028
import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper';
3129
import { WorkspacePreQueryHookPayload } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type';
3230
import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service';
3331
import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api-key-role.service';
32+
import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard';
33+
import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard';
34+
import { isWorkspaceAuthContext } from 'src/engine/core-modules/auth/guards/is-workspace-auth-context.guard';
3435
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
36+
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
3537
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
3638
import { MetricsService } from 'src/engine/core-modules/metrics/metrics.service';
3739
import { MetricsKeys } from 'src/engine/core-modules/metrics/types/metrics-keys.type';
@@ -287,10 +289,14 @@ export abstract class CommonBaseQueryRunnerService<
287289

288290
const userHasPermission =
289291
await this.permissionsService.userHasWorkspaceSettingPermission({
290-
userWorkspaceId: authContext.userWorkspaceId,
292+
userWorkspaceId: isUserAuthContext(authContext)
293+
? authContext.userWorkspaceId
294+
: undefined,
291295
setting: permissionRequired,
292296
workspaceId: workspace.id,
293-
apiKeyId: authContext.apiKey?.id,
297+
apiKeyId: isApiKeyAuthContext(authContext)
298+
? authContext.apiKey.id
299+
: undefined,
294300
});
295301

296302
if (!userHasPermission) {
@@ -363,7 +369,7 @@ export abstract class CommonBaseQueryRunnerService<
363369

364370
private async throttleQueryExecution(authContext: WorkspaceAuthContext) {
365371
try {
366-
if (!isDefined(authContext.apiKey)) return;
372+
if (!isApiKeyAuthContext(authContext)) return;
367373

368374
const workspaceId = authContext.workspace.id;
369375

packages/twenty-server/src/engine/api/common/common-query-runners/common-create-many-query-runner/common-create-many-query-runner.service.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import { ObjectRecord } from 'twenty-shared/types';
66
import { isDefined } from 'twenty-shared/utils';
77
import { FindOptionsRelations, In, InsertResult, ObjectLiteral } from 'typeorm';
88

9-
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
10-
9+
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
1110
import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service';
1211
import { PartialObjectRecordWithId } from 'src/engine/api/common/common-query-runners/common-create-many-query-runner/types/partial-object-record-with-id.type';
1312
import { buildWhereConditions } from 'src/engine/api/common/common-query-runners/common-create-many-query-runner/utils/build-where-conditions.util';

packages/twenty-server/src/engine/api/common/common-query-runners/common-create-one-query-runner.service.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import { Injectable } from '@nestjs/common';
22

33
import { type ObjectRecord } from 'twenty-shared/types';
44

5-
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
6-
5+
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
76
import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service';
87
import { CommonCreateManyQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-create-many-query-runner/common-create-many-query-runner.service';
98
import { CommonBaseQueryRunnerContext } from 'src/engine/api/common/types/common-base-query-runner-context.type';

packages/twenty-server/src/engine/api/common/common-query-runners/common-delete-many-query-runner.service.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import { ObjectRecord } from 'twenty-shared/types';
55
import { isDefined } from 'twenty-shared/utils';
66
import { FindOptionsRelations, ObjectLiteral } from 'typeorm';
77

8-
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
9-
8+
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
109
import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service';
1110
import {
1211
CommonQueryRunnerException,

packages/twenty-server/src/engine/api/common/common-query-runners/common-delete-one-query-runner.service.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import { msg } from '@lingui/core/macro';
44
import { type ObjectRecord } from 'twenty-shared/types';
55
import { isDefined } from 'twenty-shared/utils';
66

7-
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
8-
7+
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
98
import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service';
109
import { CommonDeleteManyQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-delete-many-query-runner.service';
1110
import {

packages/twenty-server/src/engine/api/common/common-query-runners/common-destroy-many-query-runner.service.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import { ObjectRecord } from 'twenty-shared/types';
55
import { isDefined } from 'twenty-shared/utils';
66
import { FindOptionsRelations, ObjectLiteral } from 'typeorm';
77

8-
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
9-
8+
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
109
import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service';
1110
import {
1211
CommonQueryRunnerException,

packages/twenty-server/src/engine/api/common/common-query-runners/common-destroy-one-query-runner.service.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import { msg } from '@lingui/core/macro';
44
import { type ObjectRecord } from 'twenty-shared/types';
55
import { isDefined } from 'twenty-shared/utils';
66

7-
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
8-
7+
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
98
import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service';
109
import { CommonDestroyManyQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-destroy-many-query-runner.service';
1110
import {

packages/twenty-server/src/engine/api/common/common-query-runners/common-find-duplicates-query-runner.service.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import { ObjectRecord, OrderByDirection } from 'twenty-shared/types';
99
import { isDefined } from 'twenty-shared/utils';
1010
import { FindOptionsRelations, In, ObjectLiteral } from 'typeorm';
1111

12-
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
13-
12+
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
1413
import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service';
1514
import {
1615
CommonQueryRunnerException,

packages/twenty-server/src/engine/api/common/common-query-runners/common-find-many-query-runner.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ import {
88
import { ObjectRecord, OrderByDirection } from 'twenty-shared/types';
99
import { FindOptionsRelations, ObjectLiteral } from 'typeorm';
1010

11-
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
1211
import {
1312
ObjectRecordFilter,
1413
ObjectRecordOrderBy,
1514
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
1615

16+
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
1717
import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service';
1818
import {
1919
CommonQueryRunnerException,

packages/twenty-server/src/engine/api/common/common-query-runners/common-find-one-query-runner.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import { ObjectRecord } from 'twenty-shared/types';
66
import { isDefined } from 'twenty-shared/utils';
77
import { FindOptionsRelations, ObjectLiteral } from 'typeorm';
88

9-
import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface';
109
import { ObjectRecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface';
1110

11+
import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
1212
import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service';
1313
import {
1414
CommonQueryRunnerException,

0 commit comments

Comments
 (0)