> ## Documentation Index
> Fetch the complete documentation index at: https://docs.siftstack.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authorization models settings

> Settings, options, and behaviors for Role-Based Access Control (RBAC) and Data Access Governance (DAG) in Sift.

export const MintTable = ({columns = [], rows = [], columnWidths = []}) => {
  const pushTextWithLineBreaks = (parts, text, keyBase) => {
    const segments = String(text).split(/\\n|\n/);
    segments.forEach((segment, idx) => {
      if (segment) {
        parts.push(<span key={`${keyBase}-text-${idx}`}>{segment}</span>);
      }
      if (idx < segments.length - 1) {
        parts.push(<br key={`${keyBase}-br-${idx}`} />);
      }
    });
  };
  const parseMarkdown = text => {
    if (text === null || text === undefined) return "";
    const str = String(text);
    const parts = [];
    let lastIndex = 0;
    const pattern = /(`[^`]+`|\*\*[^*]+\*\*|\*[^*]+\*|\[([^\]]+)\]\(([^)]+)\))/g;
    let match;
    while (true) {
      match = pattern.exec(str);
      if (match === null) {
        break;
      }
      if (match.index > lastIndex) {
        pushTextWithLineBreaks(parts, str.substring(lastIndex, match.index), `before-${lastIndex}`);
      }
      const fullMatch = match[0];
      if (fullMatch.startsWith("`") && fullMatch.endsWith("`")) {
        parts.push(<code key={match.index}>{fullMatch.slice(1, -1)}</code>);
      } else if (fullMatch.startsWith("**") && fullMatch.endsWith("**")) {
        parts.push(<strong key={match.index}>{fullMatch.slice(2, -2)}</strong>);
      } else if (fullMatch.startsWith("*") && fullMatch.endsWith("*")) {
        parts.push(<em key={match.index}>{fullMatch.slice(1, -1)}</em>);
      } else if (fullMatch.startsWith("[")) {
        const linkText = match[2];
        const linkUrl = match[3];
        parts.push(<a key={match.index} href={linkUrl} className="text-black-600 dark:text-black-400">
            {linkText}
          </a>);
      }
      lastIndex = pattern.lastIndex;
    }
    if (lastIndex < str.length) {
      pushTextWithLineBreaks(parts, str.substring(lastIndex), `tail-${lastIndex}`);
    }
    if (parts.length > 0) {
      return parts;
    }
    const plainParts = [];
    pushTextWithLineBreaks(plainParts, str, "plain");
    return plainParts.length ? plainParts : str;
  };
  const safeColumns = Array.isArray(columns) ? columns : [];
  const safeRows = Array.isArray(rows) ? rows : [];
  const safeColumnWidths = Array.isArray(columnWidths) ? columnWidths : [];
  const hasColumnWidths = safeColumnWidths.some(w => w !== null && w !== undefined && w !== "");
  const toCssWidth = width => typeof width === "number" ? `${width}px` : String(width);
  const getColumnStyle = idx => {
    const rawWidth = safeColumnWidths[idx];
    if (rawWidth === null || rawWidth === undefined || rawWidth === "") {
      return undefined;
    }
    const width = toCssWidth(rawWidth);
    return {
      width,
      minWidth: width
    };
  };
  const containerStyle = hasColumnWidths ? undefined : {
    overflowX: "auto"
  };
  const tableStyle = hasColumnWidths ? {
    tableLayout: "fixed",
    width: "100%"
  } : {
    width: "max-content",
    minWidth: "100%"
  };
  if (!Array.isArray(columns) || !Array.isArray(rows) || !Array.isArray(columnWidths)) {
    console.warn("MintTable received invalid props:", {
      columns,
      rows,
      columnWidths
    });
  }
  if (!safeColumns.length && !safeRows.length) {
    return null;
  }
  return <div className="mint-table-container" style={containerStyle}>
      <table style={tableStyle}>
        {hasColumnWidths && <colgroup>
            {safeColumns.map((_, idx) => {
    const style = getColumnStyle(idx);
    return <col key={idx} style={style} />;
  })}
          </colgroup>}
        <thead>
          <tr>
            {safeColumns.map((col, idx) => <th key={idx} className="text-left" style={getColumnStyle(idx)}>
                <b>{parseMarkdown(col)}</b>
              </th>)}
          </tr>
        </thead>
        <tbody>
          {safeRows.map((row, rIdx) => {
    const safeRow = Array.isArray(row) ? row : [];
    return <tr key={rIdx}>
                {safeRow.map((cell, cIdx) => <td key={cIdx} style={getColumnStyle(cIdx)}>
                    {parseMarkdown(cell)}
                  </td>)}
              </tr>;
  })}
        </tbody>
      </table>
    </div>;
};

Sift access control uses two strategies: Role-Based Access Control (RBAC) and Data Access Governance (DAG). RBAC is the default system. DAG is an attribute-based access control (ABAC) implementation that provides more granular control.

## RBAC vs DAG

The following table compares RBAC and DAG to help you determine which model fits your organization's needs:

<MintTable
  columns={['', 'RBAC', 'DAG']}
  columnWidths={['20%', '40%', '40%']}
  rows={[
['Best when', 'Permissions do not change often and grouping users by job function is enough to determine what they can do.', 'You need fine-grained control or when permissions depend on real-time factors rather than fixed roles.'],
['Best suited for', 'Startups in early development stage.', 'Large enterprises, EU-based companies under EU Export regulation.'],
['Limitation', 'Custom roles are not supported at this time.', 'DAG policies cannot override predefined RBAC user roles (for example, a DAG policy cannot grant Admin access to a view-only user).'],
]}
/>

<Note>
  **When to use DAG**: Not all organizations need DAG. RBAC is often easier to configure and manage. DAG is not a one-size-fits-all solution. Most organizations will find RBAC sufficient and easier to manage.
</Note>

## Role-Based Access Control (RBAC)

Role-based access control (RBAC) is the default access control system in Sift. RBAC uses predefined roles and groups to manage user permissions across resources. RBAC sets the maximum permissions a user can have. DAG can only further restrict access within that boundary.

### Roles

RBAC uses four predefined roles that determine the level of access granted to users:

* **Admin**: Full access to data, configuration settings, and user management. Admins can create and modify groups, manage users, and configure system settings.
* **Editor**: Can view, edit, and write time series data and metadata. Editors have full data access but cannot manage users or system configuration.
* **Collaborator**: Can view time series data and add metadata. Collaborators can annotate and tag data but cannot modify the underlying time series data.
* **View-only**: Read-only access to time series data. View-only users can explore and analyze data but cannot make any changes.

<Note>
  **Custom roles**: Custom roles in RBAC are not supported at this time. All organizations use these four predefined roles. For custom defined roles an organization needs to use ABAC.
</Note>

### Role permissions

The following table shows which permissions are available for each role. An `*` indicates that the role has that permission:

<MintTable
  columns={['Permission', 'Admin', 'Editor', 'Collaborator', 'View Only']}
  columnWidths={['52%', '12%', '12%', '12%', '12%']}
  rows={[
['**Assets**', '', '', '', ''],
['View assets', '*', '*', '*', '*'],
['Create asset', '*', '*', '*', ''],
['Edit asset', '*', '*', '', ''],
['**Users & Groups**', '', '', '', ''],
['Invite users', '*', '', '', ''],
['Create user group', '*', '', '', ''],
['Edit user group', '*', '', '', ''],
['View user groups', '*', '', '', ''],
['Deactivate user', '*', '', '', ''],
['**Annotations**', '', '', '', ''],
['Create annotation', '*', '*', '*', ''],
['Edit annotation', '*', '*', '*', ''],
['Create Annotation comment', '*', '*', '*', ''],
['**Data operations**', '', '', '', ''],
['Ingest data', '*', '*', '', ''],
['Create run', '*', '*', '*', ''],
['Edit run', '*', '*', '*', ''],
['**Rules**', '', '', '', ''],
['Create rule', '*', '*', '', ''],
['Edit rule', '*', '*', '', ''],
['View rules', '*', '*', '', '*'],
['Execute rule', '*', '*', '', ''],
['**Channels**', '', '', '', ''],
['Edit channel', '*', '*', '*', ''],
['Edit retention policy', '*', '*', '', ''],
['**Views**', '', '', '', ''],
['Create view', '*', '*', '*', ''],
['Edit all views', '*', '', '', ''],
['Delete all views', '*', '', '', ''],
['**Tags**', '', '', '', ''],
['Create tag', '*', '*', '*', ''],
['**API Keys**', '', '', '', ''],
['Create API key', '*', '', '', ''],
['List API keys', '*', '', '', ''],
['Edit API key', '*', '', '', ''],
['**Report Templates**', '', '', '', ''],
['Create Report Template', '*', '*', '', ''],
['Edit Report Template', '*', '*', '', ''],
['View Report Template', '*', '*', '*', '*'],
['**Reports**', '', '', '', ''],
['Create Report', '*', '*', '', ''],
['Edit Report', '*', '*', '', ''],
['View Report', '*', '*', '*', '*'],
['**Campaigns**', '', '', '', ''],
['Create Campaign', '*', '*', '', ''],
['Edit Campaign', '*', '*', '', ''],
['View Campaign', '*', '*', '*', '*'],
['**Calculated Channels**', '', '', '', ''],
['Create Calculated Channel', '*', '*', '', ''],
['Edit Calculated Channel', '*', '*', '', ''],
['View Calculated Channel', '*', '*', '*', '*'],
['**User-Defined Functions**', '', '', '', ''],
['Create User-Defined Function', '*', '*', '', ''],
['Edit User-Defined Function', '*', '*', '', ''],
['View User-Defined Function', '*', '*', '*', '*'],
['**Webhooks**', '', '', '', ''],
['Create Webhook', '*', '*', '', ''],
['Edit Webhook', '*', '*', '', ''],
['View Webhook', '*', '*', '*', '*'],
['**External sync**', '', '', '', ''],
['Edit external sync', '*', '', '', ''],
['View external sync', '*', '', '', ''],
['**Metadata**', '', '', '', ''],
['Delete Metadata', '*', '', '', ''],
['**Test Reports**', '', '', '', ''],
['Create test Report', '*', '*', '', ''],
['Edit test report', '*', '*', '', ''],
['View test report', '*', '*', '*', '*'],
['Delete test Report', '*', '*', '', ''],
['**Panel configuration**', '', '', '', ''],
['Edit panel configuration', '*', '', '', ''],
]}
/>

### Groups

Groups are collections of users that share the same role and Asset access permissions. Groups simplify access management by allowing administrators to assign permissions to multiple users at once.

Key characteristics of groups:

* **Role assignment**: Each group is assigned one of the four predefined roles (Admin, Editor, Collaborator, or View-only).
* **User membership**: Users can belong to one or more groups, inheriting permissions from all groups they belong to.
* **Default groups**: Internal users (those with email addresses matching the organization's domain) are automatically added to a default group during sign-up. External users are assigned to a specified group during invitation.

### Asset access

Asset access determines which resources (Runs, Channels, Reports, etc.) a group can access. Groups can be configured with:

* **All assets**: Access to all resources in the organization.
* **Specific assets**: Access restricted to a defined subset of Assets.

This allows administrators to create groups with the same role but different data access. For example, you might have an "Engine Team - Editors" group with Editor role and access to Engine Assets, and a "Propulsion Team - Editors" group with Editor role and access to Propulsion Assets.

### How permissions work

Permissions in RBAC are determined by a user's group memberships:

1. **Group role**: Each group has a role that defines what actions its members can perform.
2. **Asset access**: Each group has access to either all Assets or a specific subset of Assets.
3. **Combined permissions**: When a user belongs to multiple groups, they inherit the union of permissions from all groups. For example, if a user belongs to a group with Editor role and access to Engine Assets, and another group with Collaborator role and access to Propulsion Assets, they will have Editor permissions on Engine Assets and Collaborator permissions on Propulsion Assets.

## Data Access Governance (DAG)

DAG controls access using attributes assigned to users and resources. While RBAC uses fixed roles to set the boundary of what a user can do, DAG evaluates attribute-based policies to further restrict access within that boundary.

<Note>
  **How RBAC and DAG work together**: DAG does not replace RBAC. RBAC sets the maximum permissions a user can have. DAG can only further restrict access within that boundary. A DAG policy cannot grant permissions that the user's RBAC role forbids.
</Note>

### User attributes

User attributes are key-value pairs that describe who a user is. You can assign attributes directly in Sift or sync them from an Identity Provider (IdP).

### Resource attributes

Resource attributes are key-value pairs that describe Sift resources. DAG uses them alongside user attributes to evaluate policies.

#### Supported resource types

You can assign attributes to the following resource types:

* **Assets**
* **Channels**
* **Runs**

#### Access inheritance

DAG enforces access inheritance between related resources:

* **Channels inherit from their parent Asset.** If a user is denied an action on an Asset, the same action is denied on all of that Asset's Channels, even if a separate policy allows it on the Channel. The Asset-level decision always wins.
* **Runs check Asset access only for `viewData`.** To view telemetry data on a Run, the user must have `viewData` access to at least one of the Run's associated Assets. If all associated Assets deny `viewData`, the Run is denied too. Other actions on Runs (such as `editDetails` or `archive`) are evaluated on the Run alone.

#### Attribute data types

The following table describes the supported data types for attributes:

<MintTable
  columns={['Data type', 'Description', 'When to use', 'Example']}
  columnWidths={['15%', '25%', '35%', '25%']}
  rows={[
['Boolean', 'True or false.', 'Binary states with no chance of a third option.', '`IsOnSite: true`'],
['Enum', 'A single value from a predefined set.', 'Mutually exclusive categories.', '`department: "Engineering"`'],
['Enum Set', 'Multiple values from a predefined set.', 'Non-exclusive memberships or multi-label tagging.', '`clearance: ["ITAR", "EAR"]`'],
['Integer', 'A numeric value.', 'Ordered levels or thresholds that need comparison operators (`>`, `<`, `=`).', '`clearance_level: 5`'],
]}
/>

<Tip>
  **Best practice**: Use Enum instead of Boolean for statuses like employment type. It is easier to add a third value (for example, "Part-Time") to an Enum than to restructure Boolean logic later.
</Tip>

#### Attribute key uniqueness

Attribute key names must be unique across your organization. You cannot create two attributes with the same name, even if they have different data types.

### Policies

Policies define the logic that governs access.

#### Evaluation model

Sift evaluates access in two layers:

<MintTable
  columns={['Layer', 'Function', 'Description']}
  columnWidths={['15%', '25%', '60%']}
  rows={[
['RBAC', 'Sets the boundary', "The user's RBAC role determines the maximum set of permitted actions and resource access. DAG cannot expand this boundary."],
['DAG', 'Restricts within the boundary', 'If RBAC allows the action, Sift evaluates DAG policies. These policies can further deny access to specific resources.'],
]}
/>

DAG uses a **default-deny** model. For a user to access a DAG-controlled resource, there must be at least one `allow` policy that matches. If no policy matches, access is denied.

<Note>
  **Initial setup**: When DAG is first enabled for an organization, a blanket allow policy is typically configured so that existing access is preserved. Specific `deny` policies are then added to restrict sensitive resources. Without a blanket allow, all non-admin users lose access to DAG-controlled resources.
</Note>

#### Precedence

When multiple policies match, Sift resolves them using strict precedence:

<MintTable
  columns={['Rule', 'Behavior']}
  columnWidths={['30%', '70%']}
  rows={[
['Explicit deny wins', 'If any `deny` policy matches, access is denied immediately, regardless of any `allow` policies.'],
['Explicit allow', 'If at least one `allow` policy matches and no `deny` policy matches, access is granted (provided RBAC also allows the action).'],
['No match', 'If no policies match the user and resource, access is denied (default deny).'],
]}
/>

#### Actions

Every policy must define which actions are allowed or denied. The `viewDetails` action serves as a prerequisite for all other operations. If a user cannot `viewDetails` on a resource, all other actions on that resource are automatically denied. The following table lists all available actions:

<MintTable
  columns={['Action', 'Category', 'Description']}
  columnWidths={['20%', '15%', '65%']}
  rows={[
['`ingestData`', 'Create', 'Ingest time-series data into Sift.'],
['`createRun`', 'Create', 'Create new Runs in Sift.'],
['`viewDetails`', 'Read', 'View resource metadata, listings, and overview details. Prerequisite for all other actions.'],
['`viewData`', 'Read', 'Read telemetry data values from Channels, Runs, and Assets.'],
['`export`', 'Read', 'Export data from Sift.'],
['`editDetails`', 'Update', 'Modify resource name, description, and properties.'],
['`editTags`', 'Update', 'Add, modify, or remove tags on resources.'],
['`editMetadata`', 'Update', 'Add, modify, or remove Metadata on resources.'],
['`archive`', 'Delete', 'Archive resources (soft delete).'],
]}
/>

#### Policy settings

The following table describes the settings available when creating or editing a policy:

<MintTable
  columns={['Setting', 'Description']}
  columnWidths={['25%', '75%']}
  rows={[
['Policy name', 'Name of the policy.'],
['Description', 'Optional description of what the policy does.'],
['Effect', 'Determines whether the policy grants or blocks access (Allow or Deny).'],
['All users or Selected user groups', 'Determines whether the policy applies to all users or only selected user groups.'],
['Resource types', 'Select the resource types this policy applies to (Asset, Channel, Run).'],
['Actions', 'Select which actions users can perform on the selected resources.'],
]}
/>

#### Operators by attribute data type

The following table lists the available operators for each attribute data type:

<MintTable
  columns={['Attribute data type', 'Operators', 'Value input']}
  columnWidths={['20%', '45%', '35%']}
  rows={[
['Boolean', '`=` (equals)', 'True or False'],
['Enum', '`=` (equals), `≠` (not equals)', 'Select from predefined enum values'],
['Integer', '`=` (equals), `>` (greater than), `<` (less than), `≥` (greater than or equal), `≤` (less than or equal)', 'Numeric input'],
['Enum Set', '`Contains` (has a specific value), `Contains All` (has every listed value), `Contains Any` (has at least one listed value), `Intersects With` (overlaps with another attribute), `Is Empty` (has no values)', 'Single value, multiple values, or another attribute. No value needed for Is Empty.'],
]}
/>

<Note>
  **User group operators**: When the attribute type is **User group**, only Enum Set operators are available (`Contains`, `Contains All`, `Contains Any`, `Intersects With`, `Is Empty`). The `Intersects With` operator compares a user group's attribute against a resource attribute, enabling dual-match conditions without specifying fixed values.
</Note>

#### Admin bypass

By default, users with the Admin RBAC role bypass DAG policy evaluation entirely. Admin access is governed solely by RBAC.

## Best practices

### Plan your policy

Define the scope before configuring anything.

* **Subject**: Who is affected (internal staff, contractors, systems)?
* **Object**: Which resources are being protected?
* **Action**: Should the policy allow or deny access?

### Organize with groups

Apply policies to user groups, not individual accounts. Create dedicated groups for specific needs (for example, a Vendor-Access-Group). This simplifies auditing because you can remove a user from the group instead of updating multiple policies.

### Choose the right attribute type

<MintTable
  columns={['Data type', 'Description', 'When to use', 'Example']}
  columnWidths={['15%', '25%', '35%', '25%']}
  rows={[
['Boolean', 'True or false.', 'Binary states with no chance of a third option.', '`IsOnSite: true`'],
['Enum', 'A single value from a predefined set.', 'Mutually exclusive categories.', '`department: "Engineering"`'],
['Enum Set', 'Multiple values from a predefined set.', 'Non-exclusive memberships or multi-label tagging.', '`clearance: ["ITAR", "EAR"]`'],
['Integer', 'A numeric value.', 'Ordered levels or thresholds that need comparison operators (`>`, `<`, `=`).', '`clearance_level: 5`'],
]}
/>

### Use dual-match conditions

Require matching attributes on both the user and the resource. For example, to restrict access to Artemis Mission assets, create an `intersect` policy with two conditions:

1. User has `Mission = Artemis`
2. Resource has `Mission = Artemis`

Access is granted only when both conditions are satisfied.

### Naming conventions

* **PascalCase**: `EmploymentStatus`, `ClearanceLevel`
* **Subject-property pattern**: `UserDepartment`, `ResourceProject`
* **Boolean prefixes**: `IsActive`, `HasMFA`
* **Avoid redundancy**: Use `ClearanceLevel`, not `ClearanceLevelInteger`

## FAQs

### What happens if I don't assign attributes to a resource?

If no DAG policies target a resource, access depends on your policy configuration. With a blanket allow policy in place, the resource is accessible to anyone whose RBAC role allows it. Without a blanket allow, unmatched resources are denied by default.

### Can I restrict access to specific Channels?

Yes. You can assign resource attributes to individual Channels and Runs, not just Assets.

For example, you can allow a user to see an Asset but deny access to a specific sensitive Channel within that Asset. Note that the reverse also applies: if access to an Asset is denied, all Channels belonging to that Asset are also denied.

### What happens if a user matches multiple policies?

Sift prioritizes security: if any matching `deny` policy denies access, access is denied immediately, regardless of any `allow` policies. Access is only granted when at least one `allow` matches and no `deny` applies.

## Behavior

The following table describes known constraints and behaviors to be aware of when working with authorization models in Sift:

<MintTable
  columns={['Limitation', 'Description']}
  columnWidths={['30%', '70%']}
  rows={[
['RBAC custom roles', 'Custom roles are not supported at this time.'],
['DAG policy limits', 'DAG policies cannot override predefined RBAC user roles. For example, a DAG policy cannot grant Admin access to a view-only user.'],
]}
/>
