Skip to main content
Version: Target · roadmap

Permissions

Who is allowed what. A permission is a rule policy that bears on the actor rather than on the action; it reads the identity established at the door.

Everything is closed, grants open operations​

By default, nobody is allowed anything. A profile receives operations of the tenant's APIs, named by their API: boutique.searchProducts, boutique.createOrder. An operation that none of the identity's profiles received is never called for it.

profiles:
anonyme:
when: "identity.authenticated == false"
grants: [boutique.searchProducts, boutique.createOrder]
premium:
when: "identity.authenticated and 'premium' in identity.plans"
grants: [boutique.searchProducts, boutique.createOrder]
support:
when: "'support' in identity.roles"
grants: [paiement.proposeRefund, paiement.createRefund]
manager:
when: "'support-manager' in identity.roles"
grants: [paiement.proposeRefund, paiement.createRefund]
  • A grant bears on the operation, not on the skill. One operation can be reached by a skill, a playbook task, the submit or an automation: guarding it guards them all.
  • Grants add up across the profiles of one identity.
  • Grants are the only place that opens. Everything else (permissions, guards, budgets, approvals, sub-identities) only tightens what they opened.
  • The anonymous visitor gets no exception: what it may do, the anonyme profile receives.
  • Operations are a closed set, read from the OpenAPI: a grant naming an unknown operation is refused at load time.
  • Core checks the grant when it calls the tenant's API, reading the config again. Even if the compiled graph were wrong, the call would be refused.

Permissions tighten, phase by phase​

Within what grants opened, a permission guard reserves a precise moment to some profiles. Each phase answers one question:

phasequestionwhat rules it
invokewho may call the skill?the grant of the operation read, then a permission in invoke.guards; on return, kinds classify the items
presentwhich kinds are shown, and to whom?a permission in kinds.<k>.present
selectwho may choose which kind?a permission in select or kinds.<k>.select
submitwho may submit?the grant of the write operation, and submitted_by

A skill has no right of its own: it can be used if the operations it calls are granted, and if its permissions allow it. A playbook opens if its required tasks can be done. An automation has no profile of its own: what it starts acts under the room's owner it names (owner), with that owner's grants.

For a rule used only once, a require guard on the identity is enough, without creating a profile: require: "'phone' in identity.verified".

When a proof can open the rule, Core does not only refuse: it asks for authentication, before the call for invoke and present, at the choice for select, at the submit for submit, then runs the call again. See Asking for authentication.

What a profile sees: the permission in present​

Customers who are not premium do not see premium products:

skills:
- name: articles
invoke: {method: searchProducts}
kinds:
premium:
when: "$fields.tier == 'premium'"
present: {guards: [{permission: {profiles: [premium]}}]}
present:
fields:
name: {from: name, type: text, role: title}
tier: {from: tier, type: text}

A permission in present is a security rule, not a display choice:

  • Core removes the item from the result before the model, on both doors. Neither the model nor the widget sees it.
  • Counts are made after the filter: "12 products" does not betray the hidden ones.
  • What you cannot see, you cannot choose: select inherits from present. Otherwise the model could add a premium product by guessing its id.
  • When the tenant's API can filter, pass it the filter, through a parameter set by the identity (set_by: [identity]). The premium product then never leaves the tenant.

per_profile.present without a permission stays interface: more columns for a manager. See Profiles.

Reserving a kind to the choice​

skills:
- name: rembourser
invoke: {method: proposeRefund}
kinds:
gros-montant:
when: "$fields.amount > 50"
select: {guards: [{permission: {profiles: [manager]}}]} # support sees, the manager chooses
present:
fields:
name: {from: label, type: text, role: title}
amount: {from: amount, type: price, role: billed}

Support sees the large refund and can flag it; only the manager can choose it.

Rules combine by intersection: an action is allowed only if every layer allows it (station, skill, playbook, profile, sub-identity). See How the layers combine. That these layers do not contradict each other is checked at load time by the permission graph.

Who submits​

The right to submit is set in the submit_guard, by submitted_by: the room's verified owner, the person who sent the agent, the approver, a role, or the agent itself under a condition. Whoever submits must also hold the grant of the write operation. See The submit.

Delegated sub-identities​

A customer of the station creates sub-identities for its agents, on the tenant's page. Their limits — amount, hours, addresses, forbidden skills, confirmation above an amount — are rules like the others. They can only restrict; a limit that would widen the station is refused. The station declares what it lets be limited in station.delegation.restrictions.