Skip to main content
Version: main 🚧

Problem Statement: Centralized BFF Authorization & PDP-Agnostic API

Status: Draft for second-opinion review
Date: 2026-06-05
Authors: Sri Aradhyula (problem framing); AI-assisted synthesis from PR review + team discussion
Audience: Platform engineers, security architects, agents reviewing implementation options

Related work:

LinkRole
PR #1751Workflow RBAC visibility, run access, unsaved UX, agent-access modal
PR #1751 review r3362688683@subbaksh: workflows are UI/BFF concept; DA should not own workflow RBAC
Issue #1742Epic: RBAC/Auth review remediation (PR #1444 follow-ups)
Issue #1755Skills RBAC UI parity / shared-module hygiene (#1727 follow-up)
Issue #1455Runtime BFF ReBAC endpoints for Slack/Webex bots
Issue #1454Refactor DA runtime auth surface
Issue #1731Duplicate OpenFGA can_use on DA chat path
Issue #1734–#1738RAG thin PEP / Mongo in hot path

1. Executive summary​

CAIPE has reusable RBAC modules on the BFF (Next.js UI server) and CI guards for new resource types, but authorization is still implemented inconsistently across surfaces:

  • Dynamic Agents (DA) sometimes reads MongoDB for UI-domain data (e.g. workflow_configs, teams) and duplicates OpenFGA checks the BFF already performs.
  • RAG still uses a monolithic server/rbac.py that mixes token validation, legacy roles, OpenFGA, and MongoDB β€” a different pattern than agents/KB/MCP on the BFF.
  • Public APIs and errors expose OpenFGA-specific concepts (agent#use, pdp_denied, tuple strings), coupling integrators and UI copy to the current PDP.
  • HTTP authorization is fragmented: admin-only rebac/check, domain-specific access-check routes, and no generic runtime evaluate API for service callers (bots, DA).

After testing 0.5.9 and reviewing PR #1751, the team wants to:

  1. Stop creating anti-patterns (DA β†’ Mongo for workflows; one-off RBAC per resource).
  2. Enforce shared module usage going forward (linters, hygiene).
  3. Make the authorization API PDP-agnostic so OpenFGA is an implementation detail, not a user-facing contract.
  4. Centralize policy decisions on the BFF where platform domain data lives (workflows, teams, visibility).

This document captures the problem statement, current state, stakeholder input, and implementation options for a follow-up spec.


2. Problem statement​

2.1 Core problem​

Authorization logic and platform domain data are scattered across BFF, Dynamic Agents, RAG, and Slack bot, with multiple parallel patterns for the same decision (user X may use resource Y). This causes:

  1. Architectural drift β€” reviewers repeatedly flag DA/RAG reading Mongo or re-implementing visibility rules that belong on the BFF.
  2. Duplicate PDP hops β€” BFF checks OpenFGA, then DA checks OpenFGA again (latency, availability, confusion about source of truth).
  3. Inconsistent developer experience β€” agents use shareable-resource.ts + resource-authz.ts; RAG uses rbac.py; workflows added DA-side Mongo reads in PR #1751.
  4. Leaky abstraction β€” API consumers see OpenFGA relation names and PDP jargon instead of stable product-level denial reasons.
  5. Weak enforcement β€” CI guarantees new types are registered and default-deny tested, but does not force routes/services to use shared modules vs ad-hoc checks.

2.2 Triggering incidents (this conversation)​

A. PR #1751 β€” workflow RBAC + DA delegation​

PR #1751 adds:

  • BFF: workflow visibility, run access gates, team slug normalization, unsaved UX, agent-access modal on save.
  • DA: workflow_execution_authz.py β€” reads workflow_configs and teams from Mongo; allows agent#can_use bypass when workflow_config_id is passed on chat requests.

Reviewer feedback (@subbaksh, r3362688683):

Workflows are purely a UI server concept. The UI invokes agents one step at a time. DA usually has no clue whether it's a workflow or a user chatting. For invocation β€” the DA server just has a tool (with workflow_id param) that it calls to invoke a workflow. The RBAC for invocation should be in UI server no?

Assessment: The reviewer is aligned with epic #1742. Workflow lifecycle auth already exists on the BFF (/api/workflow-runs, workflow-config-rebac.ts). DA Mongo reads are an anti-pattern; the bypass exists only because the workflow engine forwards the user JWT to DA and DA enforces agent#can_use independently.

B. Reusable modules β€” one path did not use them​

Shared modules were introduced for unified shareable resource RBAC (spec 2026-06-03-unified-shareable-resource-rbac):

  • Write path: ui/src/lib/rbac/shareable-resource.ts β†’ openfga-owned-resources.ts (reconcileShareableResource)
  • Read path: ui/src/lib/rbac/resource-authz.ts (requireResourcePermission, filterResourcesByPermission)

Skills team sharing was fixed in #1729 to use reconcileShareableResource. Follow-up #1755 tracks optional UI DRY (useShareableTeams hook) and documents explicit non-goals (skills as owner-team resources).

Gap: Not every feature path uses the shared stack. PR #1751’s DA workflow auth is the latest example of bypassing BFF modules entirely.

C. Team discussion (Kevin Kantesaria, 2026-06-05)​

Paraphrased Slack thread:

SpeakerPoint
SriCreated #1755 to track cleanup after reusable modules; one instance did not use them.
KevinPush cleanup soon so we don’t keep creating anti-patterns; unsure how to enforce going forward.
SriAdded basic RBAC enforcement for new resources; need linters and hygiene.
KevinDoes that enforcement use the modules? Original problem: RAG and agents used different RBAC setups β€” want to avoid that.
Kevin / SriMake OpenFGA less obvious to end users; API should be agnostic if we switch PDP.

2.3 Goals (desired end state)​

  1. Single policy ownership β€” BFF owns platform domain data (workflows, teams, visibility) and composes FGA + product rules.
  2. Single module stack β€” application code uses shareable-resource / resource-authz (or a thin facade), not raw openfga.ts or service-local Mongo policy.
  3. PDP-agnostic public contract β€” HTTP and user-facing errors use { resource, action, reason }, not can_use / agent#use / pdp_denied.
  4. Thin PEPs downstream β€” DA, RAG, bots either trust BFF decisions via API or verify signed claims; they do not read workflow_configs from Mongo for authz.
  5. Enforceable in CI β€” import boundaries, create-path linter extensions, no new anti-patterns without explicit spec exception.

2.4 Non-goals (for initial spec)​

  • Replacing OpenFGA as the relationship store (unless a separate strategic decision).
  • Removing all OpenFGA checks from DA in v1 (tracked as #1731; depends on #1458 dual-gate documentation).
  • Migrating skills to owner-team model (#1708) β€” separate from this problem.

3. Current state (as of 2026-06-05, branch prebuild/feat/workflow-rbac-visibility-unsaved)​

3.1 BFF authorization layers​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ BFF route handler (ui/src/app/api/**/route.ts) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β–Ό β–Ό β–Ό
requireRbacPermission requireResourcePermission Domain helpers
(api-middleware.ts) (resource-authz.ts) (workflow-config-rebac,
org/capability gates slack-channel-rebac, …)
β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β–Ό
checkOpenFgaTuple / checkUniversalRebacRelationship
(openfga.ts)
β–Ό
OpenFGA HTTP API

Key modules​

ModulePathResponsibility
OpenFGA transportui/src/lib/rbac/openfga.tscheckOpenFgaTuple, tuple read/write/reconcile
Resource ReBACui/src/lib/rbac/resource-authz.tsrequireResourcePermission, filterResourcesByPermission, requireAgentPermission, requireSkillPermission
Agent use (chat proxy)ui/src/lib/rbac/openfga-agent-authz.tsrequireAgentUsePermission β€” used by /api/v1/chat/*
Agent use (audit path)ui/src/lib/rbac/pdp-shared.tsevaluateAgentAccess β€” direct + team-union with reason codes
Shareable writeui/src/lib/rbac/shareable-resource.tshandleShareableResourceWrite, resolveShareableOwnershipWrite
FGA reconcileui/src/lib/rbac/openfga-owned-resources.tsreconcileShareableResource
Workflow policyui/src/lib/rbac/workflow-config-rebac.tsVisibility, workflowDelegatesAgentUse, reconcileWorkflowConfigAccess (uses reconcileShareableResource)
Access explain (admin)ui/src/lib/rbac/access-explainer.tsexplainAccess + Mongo provenance
Type registryui/src/types/rbac-universal.tsUniversalRebacResourceType, UniversalRebacRelationship
Enforcement manifestui/src/lib/rbac/fga-enforcement-manifest.tsPer-type rebac_enforced / surfaces for auditors

HTTP APIs that expose authorization today​

EndpointAuth gatePurposeRuntime-safe?
POST /api/admin/rebac/checkadmin_ui#viewExplain access (explainAccess)No β€” admin only
POST /api/integrations/slack/.../access-checkSession + slack_channel#readcheckSlackChannelAccessPartial β€” bot path evolving
POST /api/integrations/webex/.../access-checkSame patternWebex space accessPartial
POST /api/admin/slack/.../access-checkAdminDiagnosticsNo
POST /api/admin/openfga/relationshipAdminTuple grant/revokeNo (write)
POST /api/workflow-runsassertCanExecuteWorkflowRunsForConfigIdStart runYes β€” domain API
POST /api/workflow-configs/check-agent-accesswithAuthPre-save agent gap check (PR #1751)Yes β€” BFF-only
DA WorkflowApiClient β†’ /api/workflow-runsOAuth2 client credentialsWorkflow tools from agentsYes β€” correct pattern

There is no generic POST /api/runtime/authorize today.

Spec draft exists: docs/docs/specs/2026-05-11-identity-group-rebac/contracts/rebac-policy-api.md (POST /api/admin/rebac/check with UniversalRebacRelationship).

3.2 CI enforcement (FGA coverage guarantee, spec 2026-06-04)​

LayerArtifactWhat it enforces
1fga-type-coverage.test.tsOpenFGA model ≑ type registry ≑ chart
2fga-enforcement-manifest.test.tsEvery type classified; enforced surfaces exist on disk
3scripts/validate-fga-create-paths.pyOwnable types wire reconcile*Relationships from production routes
4default-deny-coverage.test.tsNew types auto-covered for deny-by-default

Gap: Layers 1–4 do not require routes to call shareable-resource / resource-authz vs ad-hoc checkOpenFgaTuple. They do not block DA/RAG Mongo reads for authz.

LocationMongo / policyIssue
dynamic_agents/auth/workflow_execution_authz.pyReads workflow_configs, teamsDuplicates BFF visibility; reviewer rejected
dynamic_agents/auth/openfga_authz.pyOpenFGA + workflow bypassThird auth layer on chat path
dynamic_agents/services/agent_runtime.pyReads workflow_configs for builtin tool validationShould use BFF resolve API
dynamic_agents/services/builtin_tools.pyWorkflowApiClient β†’ BFFCorrect pattern for invocation

3.4 RAG vs agents β€” divergent stacks​

ConcernAgents / BFF resourcesRAG server
Read/use gateresource-authz.ts β†’ OpenFGAserver/rbac.py (mixed)
Share/writeshareable-resource.tsPartial (KB sharing route on BFF); ingestor paths differ
Mongo in authz hot pathMostly moved to BFFStill present (#1736)
Target architectureUnified shareable resource RBACThin PEP plan

Kevin’s concern: β€œRAG and agents used different RBAC setups” β€” still true at the Python RAG layer.

3.5 PR #1751 commit inventory (relevant)​

Commit / areaBFF-aligned?Notes
Workflow run access (workflow-run-access.ts)Yes
workflow-config-rebac.ts + reconcileShareableResourceYes
Unsaved UX, team slugs, TeamMultiPickerYes
check-agent-access + WorkflowAgentAccessModalYesPre-grant agent tuples on save
workflow_execution_authz.py on DANoRemove or defer to epic
workflow_config_id on DA chat bodyNoRemove with above

3.6 User-visible OpenFGA leakage (examples)​

From openfga-agent-authz.ts and resource-authz.ts:

{
"success": false,
"error": "Permission denied",
"code": "agent#use",
"reason": "pdp_denied",
"action": "contact_admin"
}

Admin explain responses include FGA tuple strings. Audit events use pdp: "openfga". These are appropriate for operators, not for generic API consumers or end-user copy.


4. Architectural principles (agreed direction)​

  1. Workflows are a BFF concern β€” config, visibility, run orchestration, delegation checks live in UI server + workflow-engine.ts.
  2. DA invokes agents; DA workflow tools invoke workflows via BFF β€” WorkflowApiClient is the model.
  3. OpenFGA is the current PDP for relationships β€” but callers should not depend on FGA tuple shape.
  4. Defense-in-depth is optional and explicit β€” duplicate DA OpenFGA (#1731) must be a documented choice (#1458), not accidental duplication.
  5. Epic #1742 phases β€” runtime BFF endpoints (#1455) before bots/DA drop Mongo.

5. Options (detailed)​

Option 1 β€” In-process Authz facade (BFF library)​

Summary: Introduce ui/src/lib/authz/ as the only import surface for application authorization. OpenFGA moves behind a PolicyEngine interface.

Proposed structure​

ui/src/lib/authz/
index.ts # authorize(), filterAccessible(), reconcileShares()
types.ts # Subject, Resource, Action, Decision (PDP-agnostic)
errors.ts # PERMISSION_DENIED, AUTHZ_UNAVAILABLE
engines/
openfga-adapter.ts # implements PolicyEngine today
domains/
workflow.ts # workflowDelegatesAgentUse, visibility (Mongo product policy)
slack-channel.ts
webex-space.ts

Public API (sketch)​

interface AuthorizeRequest {
subject: { type: "user" | "service_account"; id: string };
resource: { type: UniversalRebacResourceType; id: string };
action: ResourcePermissionAction;
context?: Record<string, unknown>; // workflow_id, channel_id, etc.
}

interface AuthorizeDecision {
allowed: boolean;
reason: "OK" | "NO_CAPABILITY" | "AUTHZ_UNAVAILABLE" | "INVALID_REQUEST";
action?: "sign_in" | "contact_admin" | "retry";
// Admin-only extension:
debug?: { engine: string; path?: string };
}

async function authorize(req: AuthorizeRequest): Promise<AuthorizeDecision>;
async function authorizeOrThrow(req: AuthorizeRequest): Promise<void>;

Migration​

  1. Wrap existing resource-authz.ts, pdp-shared.ts, domain modules.
  2. Deprecate direct checkOpenFgaTuple imports outside lib/authz/**.
  3. Map existing ApiError codes to PDP-agnostic envelope.

Pros​

  • No new network hop; fits existing Next.js deployment.
  • Clear import boundary for ESLint.
  • Enables future non-OpenFGA engine without route changes.

Cons​

  • Does not alone fix DA/RAG β€” they don’t run inside BFF.
  • Requires disciplined migration of ~dozens of route call sites.

Enforcement​

// eslint no-restricted-imports
"@/lib/rbac/openfga" β†’ only from "@/lib/authz/**"

Option 2 β€” Runtime HTTP authorize API (BFF routes)​

Summary: Expose authorization decisions as HTTP for service callers (Slack bot, Webex bot, Dynamic Agents). Implements #1455 and generalizes access-check routes.

Proposed endpoint​

POST /api/runtime/authorize
Authorization: Bearer <user-jwt | service-account-token>
Content-Type: application/json

{
"subject": { "type": "user", "id": "<oidc-sub>" },
"resource": { "type": "agent", "id": "platform-engineer" },
"action": "use",
"context": {
"workflow_config_id": "wf-optional-hint"
}
}

Response (allow):

{
"allowed": true,
"reason": "OK"
}

Response (deny):

{
"allowed": false,
"reason": "NO_CAPABILITY",
"action": "contact_admin"
}

Response (PDP down):

{
"allowed": false,
"reason": "AUTHZ_UNAVAILABLE",
"action": "retry"
}

Domain-specific endpoints (alternative/complement)​

Instead of one generic endpoint, extend the access-check pattern:

EndpointCallerChecks
POST /api/runtime/authorizeGenericFGA + optional context handlers
POST /api/runtime/workflows/authorize-runDA, internalWorkflow visibility + step agents
POST /api/runtime/workflows/resolve-configsDAReplace Mongo workflow_configs read
Existing Slack/Webex access-checkBotsChannel/space scoped

Authentication model​

  • User bearer β€” subject must match token sub (or OBO chain).
  • Service account β€” service_account:<client_id> in FGA; may evaluate on behalf of user when context.delegated_subject is present and bot OBO is valid (needs threat model).

Pros​

  • DA/RAG/bots stop reading Mongo for policy.
  • Single HTTP contract for integrators.
  • Aligns with epic #1742 prerequisite #1455.

Cons​

  • Latency and availability β€” every DA chat could add BFF round-trip unless cached or combined with Option 3.
  • Duplicates #1731 debate if DA still checks OpenFGA after BFF says allow.

Implementation notes​

  • Implement handlers by delegating to Option 1 facade internally.
  • Admin POST /api/admin/rebac/check remains explain-only with richer debug payload.

Option 3 β€” Signed authorization claims (PEP-only downstream)​

Summary: BFF is the sole PDP. After authorize(), BFF mints a short-lived signed claim (JWT or HMAC macaroon) attached to downstream requests. DA/RAG verify signature + expiry only.

Claim sketch​

{
"iss": "caipe-bff",
"sub": "user:<oidc-sub>",
"resource": "agent:platform-engineer",
"action": "use",
"iat": 1710000000,
"exp": 1710000060,
"jti": "unique-id"
}

DA require_agent_use_permission becomes require_authorization_claim β€” no OpenFGA client in DA.

Pros​

  • Eliminates duplicate OpenFGA in DA (#1731).
  • True PDP agnostic at service boundary.
  • Workflow delegation encoded in claim issuance on BFF (no workflow_config_id on DA).

Cons​

  • Largest engineering cost: key management, revocation, clock skew, claim replay.
  • Requires #1458 dual-gate retirement plan.
  • Workflow engine currently forwards user JWT β€” would need claim issuance at run start and per step.

When to choose​

  • Phase 3+ of #1742, after runtime BFF API proves correct.

Option 4 β€” Enforcement-first (linters + manifest, minimal API change)​

Summary: Keep current modules; block anti-patterns in CI without redesigning HTTP APIs yet.

Proposed guards​

GuardMechanismBlocks
Import boundaryESLint no-restricted-importscheckOpenFgaTuple outside lib/rbac/** or lib/authz/**
Service boundaryscripts/validate-authz-boundaries.pyworkflow_configs / teams reads in dynamic_agents/** for authz
Route coverageExtend validate-fga-create-paths.py or new scriptNew routes must import from resource-authz or authz facade
Manifest updatefga-enforcement-manifest.tsAdd surfaces for task (workflows), runtime authorize routes
PR templateCheckboxβ€œUses shareable-resource / resource-authz / domain wrapper”

Pros​

  • Fastest win; addresses Kevin’s β€œdon’t create more anti-patterns.”
  • Low risk; parallel to other options.

Cons​

  • Does not fix RAG rbac.py or user-visible OpenFGA strings.
  • Does not give DA a supported API without Option 2.

Option 5 β€” Universal relationship contract (spec-only standardization)​

Summary: Standardize all checks on UniversalRebacRelationship from rbac-universal.ts β€” already in rebac-policy-api.md.

Request shape​

{
"subject": { "type": "user", "id": "user-123", "relation": "member" },
"action": "use",
"resource": { "type": "agent", "id": "platform-engineer" },
"context": { "slack_channel": "C123" }
}

Mapping​

  • Internal: checkUniversalRebacRelationship(relationship) in openfga.ts.
  • action: "use" maps to FGA relation can_use inside adapter β€” not exposed to clients.

Pros​

  • One vocabulary for docs, admin UI, runtime API, tests.
  • Natural fit for Option 1 + Option 2.

Cons​

  • action names still mirror current FGA model; true PDP swap requires adapter mapping table per engine.

6. PDP-agnostic public surface (cross-cutting)​

Regardless of option, define a stable external contract:

6.1 Error envelope migration​

CurrentTarget (public)Admin/debug only
code: "agent#use"code: "PERMISSION_DENIED"detail: "agent#use"
reason: "pdp_denied"reason: "NO_CAPABILITY"
reason: "pdp_unavailable"reason: "AUTHZ_UNAVAILABLE"
pdp: "openfga" in JSON bodyOmitKeep in audit logs
FGA tuple in error messageOmitPOST /api/admin/rebac/check

6.2 Stable reason codes​

CodeMeaningUser action hint
OKAllowedβ€”
NO_CAPABILITYDeny β€” no relationshipcontact_admin
NOT_SIGNED_INMissing/invalid authsign_in
AUTHZ_UNAVAILABLEPDP timeout/errorretry
INVALID_REQUESTBad resource id / malformedfix_request

6.3 Two-tier API​

TierAudienceOpenFGA visible?
RuntimeUI, bots, DA, RAG PEPNo
Admin explainOperators, supportYes (paths, tuples, provenance)

7. Workflow-specific resolution (PR #1751)​

7.1 Correct split of responsibility​

OperationOwnerMechanism
Create/update workflow configBFFworkflow-configs routes + reconcileWorkflowConfigAccess
Start/list/cancel/resume runBFF/api/workflow-runs + workflow-run-access.ts
Pre-save agent access gapsBFFcheck-agent-access + grant via /api/admin/openfga/relationship
Orchestrate stepsBFF workflow-engine.tsCalls DA with user auth headers
Agent #can_use at DADA OpenFGA onlyNo workflow Mongo β€” team access via pre-granted tuples or BFF-only delegation
DA workflow toolsDA β†’ BFFWorkflowApiClient /api/workflow-runs

7.2 workflowDelegatesAgentUse (exists, unused)​

Defined in workflow-config-rebac.ts:

  • Agent listed in workflow steps and
  • workflowRunAllowedByVisibility for caller

Action: Wire at POST /api/workflow-runs and optionally before each consumeAgentStream in workflow-engine.ts. Remove DA workflow_execution_authz.py.

7.3 Global workflow gap​

check-agent-access detects (all users) gaps but grant loop skips them. Spec should decide: org-wide agent grants vs admin-only warning.


PhaseScopeOptionsDepends on
0 β€” ImmediatePR #1751 cleanupRemove DA workflow Mongo; keep BFF-only RBACβ€”
1 β€” HygieneCI + docsOption 4 + #1755 UI DRYβ€”
2 β€” FacadeBFF routesOption 1 + Option 5 + error envelope Β§6Phase 1
3 β€” Runtime APIBots, DA read pathsOption 2 (#1455)Phase 2
4 β€” RAG convergencerbac.py thin PEPOption 1 client in Python or Option 2 HTTP#1734
5 β€” OptionalDA duplicate FGA removalOption 3#1458, #1731

9. Open questions for second opinion​

  1. DA execution gate: Keep OpenFGA in DA for agent#use (#1731) or move to BFF-only + signed claims (Option 3)?
  2. Workflow delegation without agent tuples: Is pre-grant on save (modal) sufficient for team workflows, or must runtime delegation work without prior grants?
  3. Generic vs domain HTTP APIs: One POST /api/runtime/authorize vs family of access-check endpoints?
  4. RAG: HTTP client to BFF vs shared Python library duplicating facade logic?
  5. Service account delegation: How should bots evaluate access for a user without admin UI perms?
  6. Claim revocation: Required for Option 3, or acceptable 60s TTL?
  7. Breaking API changes: Version /api/v2/ for error envelope, or migrate in place?
  8. Workflow task type in FGA: Is Mongo visibility a permanent product layer on top of FGA, or should all run access be FGA-only eventually?

10. Acceptance criteria (draft for full spec)​

  • No production authz path in dynamic_agents/** reads workflow_configs or teams from Mongo.
  • All new BFF routes use authorize() facade or documented domain wrapper β€” CI enforced.
  • Public API errors use Β§6 reason codes; no pdp_denied / agent#use in user-facing responses.
  • Runtime callers (Slack, Webex, DA workflow tools) use BFF HTTP or documented service contract β€” not admin rebac routes.
  • workflowDelegatesAgentUse wired at run start (and documented for step execution).
  • RAG plan references same contract as BFF (no third parallel RBAC vocabulary).
  • fga-enforcement-manifest.ts updated with new surfaces and rebac_enforced entries.
  • ADR or #1458 documents dual-gate retirement if DA OpenFGA is removed.

11. References (code & docs)​

Code​

  • ui/src/lib/rbac/shareable-resource.ts
  • ui/src/lib/rbac/resource-authz.ts
  • ui/src/lib/rbac/openfga.ts
  • ui/src/lib/rbac/workflow-config-rebac.ts
  • ui/src/lib/rbac/fga-enforcement-manifest.ts
  • ui/src/app/api/admin/rebac/check/route.ts
  • ui/src/app/api/integrations/slack/.../access-check/route.ts
  • ai_platform_engineering/dynamic_agents/src/dynamic_agents/auth/workflow_execution_authz.py
  • ai_platform_engineering/dynamic_agents/src/dynamic_agents/services/builtin_tools.py (WorkflowApiClient)
  • ui/src/lib/server/workflow-engine.ts
  • scripts/validate-fga-create-paths.py

Docs​


12. Instructions for reviewing agent​

Please evaluate:

  1. Whether Option 1 + 2 + 4 is the right default combo vs Option 3 early.
  2. Whether workflow delegation should be FGA tuples (grant on save) vs runtime BFF check only.
  3. Gaps in threat model for runtime authorize API (service account, OBO, user impersonation).
  4. Migration risk for error code changes on existing UI/clients.
  5. Whether this should be one spec or split: (a) facade + enforcement, (b) runtime HTTP API, (c) RAG/DA convergence.

Return: recommended option mix, ordered task list, and any contradictions with #1742 phasing.