Add team RBAC
Turn on managed team roles and permission enforcement.
Outcome
Organization members receive roles, and the edge enforces route read/write permissions. Use this for team products with different member responsibilities.
Prerequisites
- Routes already declared in the business
- A preview environment with a team organization
Enable RBAC
RBAC enablement is a platform-owned business setting, not code. Turn it on in the dashboard (the Access control (RBAC) card in business settings) or from the CLI:
farthershore business rbac enable
farthershore business rbac # confirm the current setting
Then enable each subscriber organization's own RBAC setting. Both flags must be
on; business enablement alone is not least-privilege enforcement. The
subscribing org can do it from its portal's Settings → Team page
(/settings/team), and you can do it from the builder plane:
farthershore consumer list <business> # find the subscriber id
farthershore consumer rbac enable <business> <subscriberId> --default-role reader
farthershore consumer rbac roles list <business> <subscriberId> # verify
Order matters: with the product flag still off, the per-subscriber call answers
400 RBAC_NOT_ENABLED_BY_PRODUCT. The business flag is shared across
environments. Do not toggle it off for tests.
Declare a stable permission group so the exact product grants are explicit:
import * as fs from "@farthershore/business";
fs.backend("api");
const requests = fs.requests();
const reports = fs.route("/v1/reports", {
get: { requireMember: true },
post: { requireMember: true },
});
const generate = fs.route("/v1/reports/generate", {
post: { requireMember: true, permission: "generate" },
});
const reportAccess = fs.group("reports", [reports, generate], {
permission: { verbs: ["generate"] },
});
fs.plan("team", {
kind: fs.plan.kind.flat,
price: fs.money.usd(49).monthly(),
grants: [reportAccess],
limits: [requests.perMinute(600)],
});
export default fs.business();
RBAC is business-level and applies to every environment. Tier-specific API access remains explicit in each plan's route or group refs. The flag takes effect at the edge automatically — no rebuild or republish is needed.
Verify
Create explicit CUSTOM product roles — from the subscriber's own portal
(/settings/team) or from the builder plane:
farthershore consumer rbac roles create <business> <subscriberId> reader \
--name Reader --permissions "reports:read"
farthershore consumer rbac assign <business> <subscriberId> <userExternalId> \
--roles reader
The platform does not seed product roles or select a default. Assign separate nonowner test members exactly these grants:
| Role | Exact grants | GET reports | POST reports | POST generate |
|---|---|---|---|---|
| Reader | reports:read | Allow | Deny | Deny |
| Writer | reports:read, reports:write | Allow | Allow | Deny |
| Generator | reports:read, reports:generate | Allow | Deny | Allow |
All allow outcomes also require an active subscription whose plan grants the route and successful identity, scope, and limit checks. Test direct API requests, not just whether a frontend button is visible. Then verify these negative cases:
- Remove the plan's route grant: a matching role still cannot grant plan access.
- Try an organization-owned credential: the example requires member identity
independently of its permission grants. For machine-callable routes that omit
requireMember, test restricted organization keys separately; RBAC still applies. - Give a role only
reports:write: it must not gainGETorgenerateaccess. - Remove all explicit grants and default-role access from a nonowner: it must not gain access. Deleted explicit role keys must not fall back to the default.
- Narrow a role and test an existing credential after edge propagation. A new token alone does not prove existing credentials have been updated.
- Attempt cross-tenant/private-record access: the backend must still enforce record ownership using verified context. Route permission is not row access.
Keep the permission vocabulary identical across environments while testing role assignments. Preview applies reconcile the shared business-wide vocabulary: renaming/deleting a group or shrinking its verbs can remove grants outside the preview. Plan that as a permission migration, not an isolated preview experiment.
Common failures
- Everyone remains unrestricted: both flags are required. Confirm the
business flag (
farthershore business rbac) and the subscriber flag — therbac.enabledfield on that subscriber'sfarthershore consumer listrow; turn it on withfarthershore consumer rbac enable <business> <subscriberId>or have the org do it at its portal's/settings/team. - A route remains unavailable: confirm the subscriber plan grants its route or group ref.
- UI hides correctly but API allows: enforce backend access through the gateway, not UI checks alone.
Recover
Repair the affected role or route grant first and repeat the denied call. The
business-wide farthershore business rbac disable removes managed role
restrictions in every environment, including production; it is an access
expansion, not a preview-only rollback. Roles are preserved for re-enable.
Keep backend record-level authorization active throughout recovery.
Next steps
See team RBAC, customer operations, and permission gates.
Agent prompt
Enable managed RBAC for this Farther Shore business with
farthershore business rbac enable(it is a platform setting, not code), then enable it for the test subscriber withfarthershore consumer rbac enable <business> <subscriberId>— enforcement needs both flags. Preserve routes and plans, test read versus write access in preview, and do not publish production.