Authorize

#Shares & Grants

When you build an app or workflow another tenant installs, controlling what those consumers can see and do is part of authoring it. Helm separates two independent levers, and you usually reason about them separately:

Tier Lever Scope Actions Where you set it
1 Share cross-tenant read only owner-side, next to the resource: /definition/*/{id}/shares, /entity/.../shares
2 Grant intra-tenant principal any of CRUD (intra) / read (cross) /access/grants

A manifest bundles many shares into one offer you provision to another tenant in a single motion (below).

Authenticate with a Personal Access Token (HTTP Basic auth) — enter it once in the Authorize bar above and every Try it below uses it.

#Tier 1 — Shares (cross-tenant, read-only)

A share is how a tenant that owns a resource (an entity type, a workflow definition, an app spec, …) declares that a specific grantee tenant may read it. That's the whole contract — shares are read-only by design:

  • ✅ Makes a resource's existence + shape visible to another tenant.
  • ✅ Lets the grantee use a shared definition (e.g. activate a shared app spec in their own tenant — the activation is theirs).
  • ❌ Never lets the grantee write to the owner's data.
  • ❌ Never materializes the owner's data inside the grantee tenant.
  • ❌ Never lets the grantee re-share onward.

Wanting create/update on a share is a sign you need a different lever: cross-tenant writes are the consumer acting on its own rows of a shared type, or a workflow that runs in the owner's tenant under an owner-controlled policy.

#Entity type shares vs entity (data) shares

For entities, two share kinds are distinct and independent:

  • An entity-type share conveys catalog + schema visibility — "this type exists, here's its shape". It never reveals the owner's rows.
  • An entity (data) share conveys row visibility — "see my rows". It requires a parent entity-type share.

This is what lets you share a type (so a partner can store their own rows of it) without exposing your rows.

POST/entity/entity-types/{id}/sharesShare a type's definition (cross-tenant, read-only)API docs ↗Try it
POST/entity/entity-types/{id}/data-sharesShare a type's rows (requires the definition share)API docs ↗Try it

#Tier 2 — Grants (intra-tenant authorization)

A grant authorizes a specific principal — a user, a team, or a policy — to act on a resource, optionally narrowed by an ABAC attribute_filter.

  • Intra-tenant grant (you own the resource): actions may be any subset of create / read / update / delete.
  • Cross-tenant grant (the resource is another tenant's): actions is constrained to ["read"], and a matching active share must also exist.
POST/access/grantsGrant a principal actions on a resourceAPI docs ↗Try it

#Combining the tiers

Within one tenant, a grant is all you need. For a cross-tenant data read you need both — a tier-1 share (owner → consumer) and a tier-2 grant (consumer → their principal):

   tier-1 share (owner → consumer)            tier-2 grant (consumer → principal)
A ──(rows of type X visible to tenant B)──► B ──(user u may read type X)──► user u

Remove the share and the cross-tenant read stops on the next request; remove the grant and the principal loses access while the share remains.

#Manifests — provision a bundle

Sharing one resource at a time is fine for a single type. To provision a whole app or workflow package to another tenant, use a manifest: a named bundle of shares, offered with two-party consent — nothing materializes until both sides act.

  1. The owner publishes the manifest to a specific grantee tenant (an offer).
  2. The grantee subscribes (accepts). Only now does each shareable item in the bundle become a read-only share inside the grantee's tenant.

Either side can pull out unilaterally — the owner rescinds the publication, or the grantee unsubscribes — and the shares disappear immediately. Every share a manifest produces is read-only, like any share.

#Provision an app spec (auto-derived manifest)

For an app you never hand-author the manifest. Declare what the app exposes in the spec's top-level shares block — shares.entityTypes (catalog + schema), shares.jsonSchemas (extra standalone schemas), and shares.entities (the only way the owner's actual rows become readable, with scope: "all" / "specific"). Then share the spec with the consumer tenant — which auto-publishes the spec's derived manifest to them:

POST/definition/specs/{id}/sharesShare an app spec (auto-publishes its manifest)API docs ↗Try it

When the consumer activates the spec (Apps) it auto-subscribes, so the bundled shares land in their tenant. To read the owner's rows, the consumer's policy still needs its own entity:<type>:read grant — the share makes the rows visible, the grant lets a principal read them.

#Provision a workflow

A workflow definition has no auto-derived manifest. Either share it directly (the consumer activates it in their own tenant, where it runs under their own policy):

POST/definition/workflows/{id}/sharesShare a workflow definition directlyAPI docs ↗Try it

…or, when the workflow needs the consumer to also see the entity types, rules, schemas, and jobs it references, bundle them all in a standalone manifest (next).

#Standalone manifests

Author a bundle of resources you own and provision it to a tenant. Each child names a resource you own (actions is always ["read"]); a child you don't own is rejected and the whole manifest rolls back. To share row data, carry both an entity_type child (catalog) and an entity child (rows) for the same type.

POST/access/manifestsAuthor a manifest bundleAPI docs ↗Try it

Publish it to a grantee tenant (an offer — no shares yet):

POST/access/manifests/{manifestId}/publicationsPublish (offer) the manifest to a tenantAPI docs ↗Try it

The grantee tenant's admin then subscribes to accept — and the bundle's shares materialize in their tenant (offers appear under GET /access/manifests?direction=incoming):

POST/access/manifests/{manifestId}/subscriptionsSubscribe (grantee accepts the offer)API docs ↗Try it

Edit a bundle later with PATCH /access/manifests/{id} (a new children array replaces the bundle and re-syncs active subscribers). Rescind with PATCH …/publications/{id} { "is_active": false }, or tear down with DELETE.

#See also

Provisioning walks the tenant-admin side (users, tokens, policies); the Canonical Example shows a tier-1 share + tier-2 grant end to end.