This issue covers spec updates, an auth pivot, dev scaffold additions, and entity provider fixes for the boost workspace — combined into a single change.
1. Staged-issues bookkeeping
Add the GitHub issue URL for issue 16 (#3597) to workspaces/boost/staged-issues.md in the boost-skills-routes section.
2. Auth pivot: RFC 8693 → OAuth2 Client Credentials
Pivot Kagenti authentication from per-user RFC 8693 token exchange to service-account OAuth2 Client Credentials Grant across all specification, openspec, and config schema files.
Config key changes
Old keys (remove):
boost.kagenti.auth.tokenExchange.enabled
boost.kagenti.auth.tokenExchange.audience
boost.kagenti.auth.tokenExchange.userTokenHeader
New keys (add):
boost.kagenti.auth.tokenEndpoint — Keycloak token endpoint URL
boost.kagenti.auth.clientId — OAuth2 client ID for service-account
boost.kagenti.auth.clientSecret — OAuth2 client secret (visibility: secret)
boost.kagenti.auth.tokenExpiryBufferSeconds — Seconds before expiry to refresh (default: 60)
Files to update
Specifications (3):
workspaces/boost/specifications/boost-context.md — Update principle 10 from "Per-User Identity Delegation" to "Service-Account Keycloak Authentication"; update augment lesson; update security PRD summary line
workspaces/boost/specifications/prd/security-safety-governance.md — Replace all RFC 8693 / token exchange references with Client Credentials Grant / KeycloakTokenManager throughout (capability 3, security mode table, architecture diagram, traceability table, customer context)
workspaces/boost/specifications/prd/platform-operations-deployment.md — Update Kagenti Auth line in configurable categories (line ~189)
OpenSpec (7):
workspaces/boost/openspec/changes/security-safety-governance/design.md — Update decision 4 and risks
workspaces/boost/openspec/changes/security-safety-governance/proposal.md — Update identity/auth section and key file reference
workspaces/boost/openspec/changes/security-safety-governance/tasks.md — Update section 7 tasks and section 10 verification tasks
workspaces/boost/openspec/changes/security-safety-governance/specs/access-control/spec.md — Replace all token exchange scenarios with service-account auth scenarios (token acquisition, streaming lifecycle, 401 retry with max-1-retry constraint, user identity propagation via X-Backstage-User header, Kagenti REST API endpoints)
workspaces/boost/openspec/changes/platform-operations-deployment/specs/runtime-config/spec.md — Update token exchange config table to Keycloak service-account fields
workspaces/boost/openspec/changes/platform-operations-deployment/tasks.md — Update task 2.5 wording
workspaces/boost/openspec/changes/pluggable-ai-platform-architecture/design.md — Update non-goal to note service-account auth adopted instead
Config/code (3):
workspaces/boost/plugins/boost-backend/config.d.ts — Replace tokenExchange nested object with flat tokenEndpoint, clientId, clientSecret, tokenExpiryBufferSeconds fields under kagenti.auth
workspaces/boost/plugins/boost-backend/src/config/schemas.ts — Bump BOOST_CONFIG_SCHEMA_VERSION to 2, replace tokenExchange.* field entries with new flat field entries, add sensitive: true to clientSecret
workspaces/boost/plugins/boost-backend/src/config/schemas.test.ts — Update test expectations for new field names; add validation tests for tokenExpiryBufferSeconds (valid integers accepted, negative rejected, non-integer rejected, undefined returns undefined)
Generated (1):
workspaces/boost/plugins/boost-backend/report.api.md — Regenerate via yarn build:api-reports
Staged issues (1):
workspaces/boost/staged-issues.md — Update issue 13 section: header, description, task list, spec references
Key design decisions
tokenExpiryBufferSeconds schema is .number().int().min(0).optional() with no .default(60) — RuntimeConfigResolver returns raw YAML values that bypass Zod defaults, so the consumer (KeycloakTokenManager) must apply configValue ?? 60
clientSecret field has sensitive: true and @visibility secret in config.d.ts
- Max-1-retry on 401: "if the retried request also returns 401, the error is propagated to the caller"
3. Spec adjustments for working dev environment
workspaces/boost/specifications/boost-context.md
- Add
boost-responses-api-toolkit and boost-toolscope to the workspace structure tree
- Update the paragraph describing the packages to mention toolscope (zero Backstage deps) and responses-api-toolkit (minimal Backstage deps)
- Add new "Local Development" section with:
- Host Packages: Explains
packages/app and packages/backend as standard Backstage scaffolding, not product code
- Metrics Compatibility Shim: Documents the no-op
metricsServiceRef factory needed because backend-defaults doesn't provide one yet (as of Backstage 1.52)
- TLS and IDE Environment Caveats:
NODE_TLS_REJECT_UNAUTHORIZED=0 for self-signed OpenShift route certs; IDE subprocess env var gotcha
workspaces/boost/specifications/prd/platform-operations-deployment.md
- Add
boost-responses-api-toolkit and boost-toolscope rows to the workspace package table
4. Backend code changes for integration testing
New files
workspaces/boost/app-config.yaml — Development-mode app-config with:
- Guest auth provider
- SQLite in-memory database
boost.security.mode: 'development-only-no-auth'
boost.providers.llamastack and boost.providers.kagenti config with env var defaults pointing at a dev cluster
boost.kagenti entity provider config with auth settings (tokenEndpoint, clientId, clientSecret from env vars)
- NOTE: All default URLs use
:- syntax for env var fallback, not hardcoded values
workspaces/boost/packages/backend/ — Host backend package:
package.json with dependencies on backend-defaults, plugin-proxy-backend, plugin-auth-backend, plugin-auth-backend-module-guest-provider, plugin-catalog-backend, plugin-catalog-backend-module-logs, plugin-permission-backend, plugin-permission-backend-module-allow-all-policy, and all boost plugins
src/index.ts with:
- No-op
metricsServiceRef factory shim (catalog-backend depends on it, backend-defaults doesn't provide it yet — uses @backstage/backend-plugin-api/alpha)
- Registration of all core Backstage plugins + all boost plugins (
boost-backend, boost-backend-module-llamastack, boost-backend-module-kagenti, kagenti-entity-provider, llamastack-entity-provider)
.eslintrc.js extending @backstage/cli/config/eslint.backend
workspaces/boost/scripts/load-secrets.sh — Shell script to load dev secrets from K8s:
- Reads
KAGENTI_CLIENT_SECRET, KAGENTI_CLIENT_ID, KAGENTI_TOKEN_ENDPOINT, KAGENTI_BASE_URL, KAGENTI_NAMESPACE, BOOST_MODEL from a K8s secret
- Sets
NODE_TLS_REJECT_UNAUTHORIZED=0
- Masks sensitive values in output (
<set> for secrets)
Modified files
workspaces/boost/plugins/kagenti-entity-provider/src/providers/kagentiAuth.ts (new file) — KeycloakAuthClient class:
- OAuth2 Client Credentials Grant token acquisition
- Token caching with expiry buffer
getBearerToken() returns cached token or fetches fresh one
- Uses
node:buffer for base64 encoding (NOT btoa which is browser-only in older Node)
workspaces/boost/plugins/kagenti-entity-provider/src/types.ts — Add KagentiEntityProviderConfig.auth optional field with tokenEndpoint, clientId, clientSecret
workspaces/boost/plugins/kagenti-entity-provider/src/module.ts — Read auth config from boost.kagenti.auth.*, construct KeycloakAuthClient when all 3 auth fields are present, pass to entity providers
workspaces/boost/plugins/kagenti-entity-provider/src/providers/KagentiAgentEntityProvider.ts:
- Accept optional
KeycloakAuthClient in constructor
- Fetch bearer token before namespace loop and add
Authorization header
- Use correct API URL:
GET /api/v1/agents?namespace={ns} (NOT /a2a/)
- Handle response shape:
{ items: AgentCard[] } OR AgentCard[] via unwrapItems helper
workspaces/boost/plugins/kagenti-entity-provider/src/providers/KagentiToolEntityProvider.ts:
- Same auth and URL pattern as agent provider
GET /api/v1/tools?namespace={ns}
- Same
unwrapItems response handling
workspaces/boost/plugins/kagenti-entity-provider/src/providers/entityHelpers.ts — Add unwrapItems<T>() helper function to handle both { items: T[] } and T[] response shapes from Kagenti API
workspaces/boost/plugins/kagenti-entity-provider/src/providers/KagentiAgentEntityProvider.test.ts and KagentiToolEntityProvider.test.ts — Add tests for Keycloak auth integration (bearer token header, auth failure handling)
workspaces/boost/plugins/boost-backend/src/mcp/routes.ts and workspaces/boost/plugins/boost-backend/src/skills/routes.ts — Add TODO comments noting future cross-reference with catalog for MCP/skill access (not functional changes, just markers)
yarn.lock
The yarn.lock will need regenerating after the dependency changes in packages/backend/package.json. Run yarn install in the boost workspace.
Verification
After all changes:
cd workspaces/boost && yarn tsc — no type errors
cd workspaces/boost && yarn test --watchAll=false — all tests pass
cd workspaces/boost && yarn build:api-reports — report.api.md up to date
cd workspaces/boost && yarn lint — clean
Security constraints
- The only references to "augment" or "Augment" should be at the high level, introductory phase, where we acknowledge that boost is a clean room re-implementation of augment (e.g., specifications/boost-context.md provenance notes and "Augment lesson" callouts)
- Do not reference any specific customer names in code or openspecs
This issue covers spec updates, an auth pivot, dev scaffold additions, and entity provider fixes for the boost workspace — combined into a single change.
1. Staged-issues bookkeeping
Add the GitHub issue URL for issue 16 (
#3597) toworkspaces/boost/staged-issues.mdin theboost-skills-routessection.2. Auth pivot: RFC 8693 → OAuth2 Client Credentials
Pivot Kagenti authentication from per-user RFC 8693 token exchange to service-account OAuth2 Client Credentials Grant across all specification, openspec, and config schema files.
Config key changes
Old keys (remove):
boost.kagenti.auth.tokenExchange.enabledboost.kagenti.auth.tokenExchange.audienceboost.kagenti.auth.tokenExchange.userTokenHeaderNew keys (add):
boost.kagenti.auth.tokenEndpoint— Keycloak token endpoint URLboost.kagenti.auth.clientId— OAuth2 client ID for service-accountboost.kagenti.auth.clientSecret— OAuth2 client secret (visibility: secret)boost.kagenti.auth.tokenExpiryBufferSeconds— Seconds before expiry to refresh (default: 60)Files to update
Specifications (3):
workspaces/boost/specifications/boost-context.md— Update principle 10 from "Per-User Identity Delegation" to "Service-Account Keycloak Authentication"; update augment lesson; update security PRD summary lineworkspaces/boost/specifications/prd/security-safety-governance.md— Replace all RFC 8693 / token exchange references with Client Credentials Grant /KeycloakTokenManagerthroughout (capability 3, security mode table, architecture diagram, traceability table, customer context)workspaces/boost/specifications/prd/platform-operations-deployment.md— Update Kagenti Auth line in configurable categories (line ~189)OpenSpec (7):
workspaces/boost/openspec/changes/security-safety-governance/design.md— Update decision 4 and risksworkspaces/boost/openspec/changes/security-safety-governance/proposal.md— Update identity/auth section and key file referenceworkspaces/boost/openspec/changes/security-safety-governance/tasks.md— Update section 7 tasks and section 10 verification tasksworkspaces/boost/openspec/changes/security-safety-governance/specs/access-control/spec.md— Replace all token exchange scenarios with service-account auth scenarios (token acquisition, streaming lifecycle, 401 retry with max-1-retry constraint, user identity propagation viaX-Backstage-Userheader, Kagenti REST API endpoints)workspaces/boost/openspec/changes/platform-operations-deployment/specs/runtime-config/spec.md— Update token exchange config table to Keycloak service-account fieldsworkspaces/boost/openspec/changes/platform-operations-deployment/tasks.md— Update task 2.5 wordingworkspaces/boost/openspec/changes/pluggable-ai-platform-architecture/design.md— Update non-goal to note service-account auth adopted insteadConfig/code (3):
workspaces/boost/plugins/boost-backend/config.d.ts— ReplacetokenExchangenested object with flattokenEndpoint,clientId,clientSecret,tokenExpiryBufferSecondsfields underkagenti.authworkspaces/boost/plugins/boost-backend/src/config/schemas.ts— BumpBOOST_CONFIG_SCHEMA_VERSIONto 2, replacetokenExchange.*field entries with new flat field entries, addsensitive: truetoclientSecretworkspaces/boost/plugins/boost-backend/src/config/schemas.test.ts— Update test expectations for new field names; add validation tests fortokenExpiryBufferSeconds(valid integers accepted, negative rejected, non-integer rejected, undefined returns undefined)Generated (1):
workspaces/boost/plugins/boost-backend/report.api.md— Regenerate viayarn build:api-reportsStaged issues (1):
workspaces/boost/staged-issues.md— Update issue 13 section: header, description, task list, spec referencesKey design decisions
tokenExpiryBufferSecondsschema is.number().int().min(0).optional()with no.default(60)—RuntimeConfigResolverreturns raw YAML values that bypass Zod defaults, so the consumer (KeycloakTokenManager) must applyconfigValue ?? 60clientSecretfield hassensitive: trueand@visibility secretin config.d.ts3. Spec adjustments for working dev environment
workspaces/boost/specifications/boost-context.mdboost-responses-api-toolkitandboost-toolscopeto the workspace structure treepackages/appandpackages/backendas standard Backstage scaffolding, not product codemetricsServiceReffactory needed becausebackend-defaultsdoesn't provide one yet (as of Backstage 1.52)NODE_TLS_REJECT_UNAUTHORIZED=0for self-signed OpenShift route certs; IDE subprocess env var gotchaworkspaces/boost/specifications/prd/platform-operations-deployment.mdboost-responses-api-toolkitandboost-toolscoperows to the workspace package table4. Backend code changes for integration testing
New files
workspaces/boost/app-config.yaml— Development-mode app-config with:boost.security.mode: 'development-only-no-auth'boost.providers.llamastackandboost.providers.kagenticonfig with env var defaults pointing at a dev clusterboost.kagentientity provider config with auth settings (tokenEndpoint, clientId, clientSecret from env vars):-syntax for env var fallback, not hardcoded valuesworkspaces/boost/packages/backend/— Host backend package:package.jsonwith dependencies onbackend-defaults,plugin-proxy-backend,plugin-auth-backend,plugin-auth-backend-module-guest-provider,plugin-catalog-backend,plugin-catalog-backend-module-logs,plugin-permission-backend,plugin-permission-backend-module-allow-all-policy, and all boost pluginssrc/index.tswith:metricsServiceReffactory shim (catalog-backend depends on it, backend-defaults doesn't provide it yet — uses@backstage/backend-plugin-api/alpha)boost-backend,boost-backend-module-llamastack,boost-backend-module-kagenti,kagenti-entity-provider,llamastack-entity-provider).eslintrc.jsextending@backstage/cli/config/eslint.backendworkspaces/boost/scripts/load-secrets.sh— Shell script to load dev secrets from K8s:KAGENTI_CLIENT_SECRET,KAGENTI_CLIENT_ID,KAGENTI_TOKEN_ENDPOINT,KAGENTI_BASE_URL,KAGENTI_NAMESPACE,BOOST_MODELfrom a K8s secretNODE_TLS_REJECT_UNAUTHORIZED=0<set>for secrets)Modified files
workspaces/boost/plugins/kagenti-entity-provider/src/providers/kagentiAuth.ts(new file) —KeycloakAuthClientclass:getBearerToken()returns cached token or fetches fresh onenode:bufferfor base64 encoding (NOTbtoawhich is browser-only in older Node)workspaces/boost/plugins/kagenti-entity-provider/src/types.ts— AddKagentiEntityProviderConfig.authoptional field withtokenEndpoint,clientId,clientSecretworkspaces/boost/plugins/kagenti-entity-provider/src/module.ts— Read auth config fromboost.kagenti.auth.*, constructKeycloakAuthClientwhen all 3 auth fields are present, pass to entity providersworkspaces/boost/plugins/kagenti-entity-provider/src/providers/KagentiAgentEntityProvider.ts:KeycloakAuthClientin constructorAuthorizationheaderGET /api/v1/agents?namespace={ns}(NOT/a2a/){ items: AgentCard[] }ORAgentCard[]viaunwrapItemshelperworkspaces/boost/plugins/kagenti-entity-provider/src/providers/KagentiToolEntityProvider.ts:GET /api/v1/tools?namespace={ns}unwrapItemsresponse handlingworkspaces/boost/plugins/kagenti-entity-provider/src/providers/entityHelpers.ts— AddunwrapItems<T>()helper function to handle both{ items: T[] }andT[]response shapes from Kagenti APIworkspaces/boost/plugins/kagenti-entity-provider/src/providers/KagentiAgentEntityProvider.test.tsandKagentiToolEntityProvider.test.ts— Add tests for Keycloak auth integration (bearer token header, auth failure handling)workspaces/boost/plugins/boost-backend/src/mcp/routes.tsandworkspaces/boost/plugins/boost-backend/src/skills/routes.ts— Add TODO comments noting future cross-reference with catalog for MCP/skill access (not functional changes, just markers)yarn.lock
The
yarn.lockwill need regenerating after the dependency changes inpackages/backend/package.json. Runyarn installin the boost workspace.Verification
After all changes:
cd workspaces/boost && yarn tsc— no type errorscd workspaces/boost && yarn test --watchAll=false— all tests passcd workspaces/boost && yarn build:api-reports— report.api.md up to datecd workspaces/boost && yarn lint— cleanSecurity constraints