Skip to main content
Domain: Auth & Privacy
Depends on: Resource Framework
RFCs: RFC-020

Abstract

This spec defines the authorization model of ODF nodes - how accounts, groups, auth attributes, actions, and policies are expressed as resources of the Resource Framework. The model is engine-agnostic: a minimal node can implement simple ownership checks, while a full node can plug in an RBAC / ABAC / ReBAC policy engine, with both remaining interoperable at the level of resources.

Terminology

This spec builds on the , , , , and concepts defined in the glossary, and introduces the following terms:
  • Subject - the party a grant is given to in a policy binding: a principal, a group, or a well-known set of principals
  • Group - a named, possibly nested set of subjects that policies can be bound to, so that permissions are granted to all members at once
  • Action - an operation the principal attempts to perform, identified by a schema URI (e.g. View, Read, Decrypt)
  • Object - the target of an action: a resource, an entity, or a resource type (for actions like Create and List where no instance exists yet)

Maturity Levels

Implementations may support authorization at one of the following maturity levels:

Accounts

Node

An ODF node. Acts as a principal in system tasks and node-to-node communications, and may own a few node-wide resources (e.g. the node/admins group).

User

An individual person who can authenticate and act as a principal.
A user may also specify a did associated with the account by ODF or an external system, and a password for local authentication, which is stored as a hash upon apply and is absent for SSO or DID-based accounts. A user can be suspended by setting disabled: true - the effects of suspension are implementation-specific.

Organization

An account that owns resources on behalf of a group of users, but cannot authenticate or act itself, so its resources are always accessed through its members.
Upon creation of an organization, the node automatically creates two groups under its account:
  • Group:acme/admins - organization administrators, initially containing the principal that created the organization. Members of this group have the same rights over resources owned by the organization as an owner would.
  • Group:acme/members - organization members
These are ordinary groups that can be edited to customize membership (e.g. by nesting team groups). Their names are reserved, so they can’t be created or deleted independently of the organization. Whether admins are implicitly considered members is left to implementations.

Service Account

A non-human identity used by automation (scheduled flows, CI, installed applications) that can act as a principal but doesn’t own resources. Service accounts are always scoped under the owning account.

Account Names

To avoid ambiguity and impersonation, nodes must ensure that names of nodes, users, and organizations are unique regardless of their resource type, making it possible to refer to any of these accounts by name alone. Service account names are exempt from this rule, as they are always scoped under the owning account. Some names cannot be used by accounts - see Reserved Names.

Ownership

Every resource is owned by the account specified in its headers.account (see Resource Framework: Ownership). Only User, Organization, and Node accounts can own resources, and are referenced using ResourceOwnerRef, whose short form is the account name. Owners hold all actions on the resources they own and on the entities materialized from them. For resources owned by an organization, the same rights are held by members of its {org}/admins group.

Principals

A principal is the identity performing an action in an authorization request. It is established through authentication and is always a single concrete identity.
  • Organization cannot authenticate - its resources are always accessed through its members.
  • Anonymous represents unauthenticated requests. It is not a resource and carries no identity.
  • When a node executes work that belongs to a user or service account (e.g. a scheduled flow run) it should do so as that principal rather than as itself.
Principals are referenced using PrincipalRef, e.g. to specify the service account a flow runs as, or to record the initiator of an operation. Its short form requires a type prefix:

Subjects

A subject is the party a grant is given to in a PolicyBinding. Unlike a principal, a subject may stand for many principals at once. Subjects are referenced using SubjectRef, which is a union of: Short forms expand as follows:
A Resource subject can alternatively be identified by id or did. Authenticated, Anonymous, and Everyone can be used in policy bindings, but not as group members - otherwise nesting such a subject into a group would extend the group’s permissions to all principals.

Groups

A Group resource represents a named set of subjects. Membership is declared inline in the spec. Groups support nesting - a group may include other groups as members. Only the Resource subject kind is allowed as a member.
Groups owned by the Node account, like Group:node/admins, can be used to represent node-wide predefined roles.

Auth Attributes

Properties of a resource that directly affect access control (e.g. whether a dataset allows public reads) are expressed using resource labels (see Resource Framework: Labels and Annotations). A label schema that declares labelProperties.isAuthAttribute: true signals that any resource carrying that label should have its value materialized into an auth attribute:
Auth attributes are set like any other label:
Rules:
  • Auth attributes must be labels, not annotations - validators must reject a resource that places an isAuthAttribute label under annotations
  • The value is validated against the label schema’s type at apply time
  • Implementations discover the set of auth attributes by enumerating label schemas with isAuthAttribute: true, rather than hardcoding a list
  • Changing an auth attribute may require elevated permissions beyond those needed to update the rest of the resource (see AddLabel)
  • Auth attributes are propagated from resources to the entities they define, e.g. AllowPublicRead on a dataset resource (control plane) also appears as an attribute of the dataset entity (data plane)
Since auth attributes are labels, they are also indexed and queryable in the resource listing API.

Standard Auth Attributes

The effects of these attributes can also be achieved by binding policies to Authenticated or Anonymous subjects. Attributes, however, are the primary way to make datasets public, as they are atomic with the resource manifest and can be efficiently filtered on when listing resources. Bindings to these subjects are better suited for granting other actions publicly, e.g. making a resource manifest viewable by everyone.

Actions

Authorization decisions are made against a set of well-defined actions. Each action is defined by a JSON schema using the Action metaschema:
  • The schema URI is the canonical action identifier used in authorization requests and policies, e.g. https://opendatafabric.org/schemas/resources/v1alpha1/actions/View
  • The schema describes the context values needed to authorize the action (e.g. the label being added for AddLabel)
  • actionProperties.objectTypes lists the types of objects the action applies to. Since resource types are an open set, every action must list its object types explicitly. Generic resource actions use the Resource type to apply to resources of any type.

Resource Actions

Operate on resource instances. Exceptions are Create and List, which operate on a resource type and receive the account under which resources are created or listed in the targetOwner context value. AddLabel and RemoveLabel operate at the sub-resource level and are distinct from Edit to allow fine-grained control - a principal may be allowed to edit a resource, but be restricted from changing auth-sensitive labels like AllowPublicRead. Their context carries the type and the new (when adding) or existing (when removing) value of the label. BindPolicy receives the subject of the binding being created in its context, so policies can restrict who is allowed to grant access to e.g. Everyone.

Dataset Actions

Operate on dataset entities in the data plane, separately from dataset resources.

Config Actions

Operate on configuration entities.

Policies and Policy Bindings

Beyond ownership, Policy and PolicyBinding resources are the primary mechanism for granting permissions:
  • A Policy is a reusable, potentially parameterized grant template. It declares what actions are permitted, but may leave the subject and object as slots to be filled in later.
  • A PolicyBinding instantiates a Policy by supplying the concrete subject (SubjectRef) and object (ResourceRef). The object refers to both the resource and the entity materialized from it.
Creating a PolicyBinding is itself an authorized operation - the principal creating it must hold the BindPolicy action on the referenced object. Resource owners implicitly hold BindPolicy on their own resources and can grant it to others, enabling delegated access management without transferring ownership. A Policy resource’s kind field selects the policy language. The Generic kind must be supported by all nodes at maturity level 2 and above. Other kinds are engine-specific. Higher-level features like dataset roles (Reader, Editor, Maintainer) are not part of this spec - implementations can build them using groups, Generic policy templates, and PolicyBinding resources.

Generic Policies

A Generic policy grants a set of ODF actions. It is the portable building block - any node at maturity level 2 and above can evaluate it without a specialized policy engine. Its subject and object are always supplied by a PolicyBinding.
The binding above grants View on the dataset resource and Read on the dataset entity.

Engine-specific Policies

Nodes with a full policy engine may support richer Policy kinds that can express attribute-based conditions, organization-scoped grants, and custom logic that Generic cannot. Engine-specific policies are not portable between implementations. Engine-specific policies may declare slots for the subject and object, in which case they are templates instantiated via PolicyBinding. Policies that don’t declare slots take effect on their own without a binding (e.g. a node-wide policy granting all actions to members of Group:node/admins). The Cedar kind carries a policy in the Cedar language, where ?principal and ?resource slots are filled in by the subject and object of a binding:
Nodes that do not support a given Policy kind must reject the resource with a clear error rather than silently ignoring it.

Access Token Scopes

Access tokens may be restricted to a set of scopes (e.g. read-only access to specific datasets). Scopes are not part of the authorization model: they can only narrow what the principal is allowed to do, so implementations check whether an action on an object falls within the token’s scopes before policy evaluation. Policies then decide based on the principal’s own permissions, so a token can never grant more than its owner has.

Reserved Names

Names that implementations must reserve and treat consistently. Accounts - the following names cannot be used by User or Organization accounts, to prevent impersonation of the node or its administrators: Matching is case-insensitive. Implementations may reserve additional names (e.g. their own product name). Groups - reserved groups are created together with the account that owns them and cannot be created or deleted independently: Subject keywords - cannot collide with resource names, as resource references in short form always include a type prefix, a DID, or an ID:

Schemas

Appendix A: Cedar Example

Non-normative: This appendix illustrates how the authorization model maps onto the Cedar policy engine.
Full prototype is available here. A schema can be code-generated based on types registered in the system allowing policies to be validated against known resource types and attributes:
Note: For brevity, actions here use short names (e.g. "read"). A generated schema would use full action schema URIs (e.g. "https://opendatafabric.org/schemas/datasets/v1alpha1/actions/Read") as in the examples above.
Example policies:
PolicyBinding resources become template-linked policies, with the ?principal slot filled based on the SubjectRef variant:

Appendix B: OpenFGA Example

Non-normative: This appendix illustrates how the authorization model maps onto the OpenFGA ReBAC engine.
Full prototype is available here.
Note: This model predates the ServiceAccount and Node principals and is kept as an illustration of how the model maps onto a ReBAC engine.
Example schema:
Last modified on October 15, 2026