From bb5258c25680db88963774031f0a8b6c7b9933fc Mon Sep 17 00:00:00 2001 From: Ludwig Bedacht Date: Fri, 1 May 2026 00:34:00 +0200 Subject: [PATCH 1/2] feat: support features claim in graph tokens --- .../federated-graph/createFederatedGraphToken.ts | 13 +++++++++++++ .../src/core/repositories/OrganizationRepository.ts | 1 + controlplane/src/types/index.ts | 4 +++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/controlplane/src/core/bufservices/federated-graph/createFederatedGraphToken.ts b/controlplane/src/core/bufservices/federated-graph/createFederatedGraphToken.ts index 337a437f13..163ff2a3ea 100644 --- a/controlplane/src/core/bufservices/federated-graph/createFederatedGraphToken.ts +++ b/controlplane/src/core/bufservices/federated-graph/createFederatedGraphToken.ts @@ -13,6 +13,7 @@ import { DefaultNamespace } from '../../repositories/NamespaceRepository.js'; import type { RouterOptions } from '../../routes.js'; import { enrichLogger, getLogger, handleError } from '../../util.js'; import { UnauthorizedError } from '../../errors/errors.js'; +import { OrganizationRepository } from 'src/core/repositories/OrganizationRepository.js'; export function createFederatedGraphToken( opts: RouterOptions, @@ -71,6 +72,17 @@ export function createFederatedGraphToken( }; } + const orgRepo = new OrganizationRepository(logger, opts.db, opts.billingDefaultPlanId); + const splitConfigFeature = await orgRepo.getFeature({ + organizationId: authContext.organizationId, + featureId: 'split-config-loading', + }); + + const features: string[] = []; + if (splitConfigFeature?.enabled) { + features.push('split-config-loading'); + } + const tokenValue = await signJwtHS256({ secret: opts.jwtSecret, token: { @@ -78,6 +90,7 @@ export function createFederatedGraphToken( federated_graph_id: graph.id, aud: audiences.cosmoGraphKey, // to distinguish from other tokens organization_id: authContext.organizationId, + features: features.length > 0 ? features : undefined, }, }); diff --git a/controlplane/src/core/repositories/OrganizationRepository.ts b/controlplane/src/core/repositories/OrganizationRepository.ts index c132f647e7..2ceb5c86cb 100644 --- a/controlplane/src/core/repositories/OrganizationRepository.ts +++ b/controlplane/src/core/repositories/OrganizationRepository.ts @@ -1420,6 +1420,7 @@ export class OrganizationRepository { sso: false, 'subgraph-check-extensions': false, support: false, + 'split-config-loading': false, }; for (const feature of features) { diff --git a/controlplane/src/types/index.ts b/controlplane/src/types/index.ts index 3cf35cf690..d438237876 100644 --- a/controlplane/src/types/index.ts +++ b/controlplane/src/types/index.ts @@ -28,7 +28,8 @@ export type FeatureIds = | 'security' | 'sso' | 'subgraph-check-extensions' - | 'support'; + | 'support' + | 'split-config-loading'; export type Features = { [key in FeatureIds]: Feature; @@ -498,6 +499,7 @@ export type AuthContext = { export interface GraphApiKeyJwtPayload extends JWTPayload { federated_graph_id: string; organization_id: string; + features?: string[]; } export interface PluginAccess { From 62a961c94d9df65ecc731842cc33cb023b78efb4 Mon Sep 17 00:00:00 2001 From: Ludwig Bedacht Date: Sat, 2 May 2026 01:01:34 +0200 Subject: [PATCH 2/2] chore: fix import --- .../bufservices/federated-graph/createFederatedGraphToken.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controlplane/src/core/bufservices/federated-graph/createFederatedGraphToken.ts b/controlplane/src/core/bufservices/federated-graph/createFederatedGraphToken.ts index 163ff2a3ea..71e2bd0870 100644 --- a/controlplane/src/core/bufservices/federated-graph/createFederatedGraphToken.ts +++ b/controlplane/src/core/bufservices/federated-graph/createFederatedGraphToken.ts @@ -13,7 +13,7 @@ import { DefaultNamespace } from '../../repositories/NamespaceRepository.js'; import type { RouterOptions } from '../../routes.js'; import { enrichLogger, getLogger, handleError } from '../../util.js'; import { UnauthorizedError } from '../../errors/errors.js'; -import { OrganizationRepository } from 'src/core/repositories/OrganizationRepository.js'; +import { OrganizationRepository } from '../../repositories/OrganizationRepository.js'; export function createFederatedGraphToken( opts: RouterOptions,