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

# Conditional Roles

Conditional roles enable advanced access control schemes including default roles and toggles.

## Default roles

In this example, organizations want members to automatically inherit a role on all repositories. Different organizations choose different default roles: some grant "viewer", others grant "admin".

Without conditional roles, you'd sync `has_role(User{"Alice"}, <default role>, Repository{"Anvils"})` for every user-repository combination. That's a lot of facts.

Instead, send one fact like `has_default_role(Organization{"acme"}, "editor")` to set a default role for their members to inherit on all of their repositories.

### Implementation

Add a custom `has_role` rule that grants the organization-configured default role on repositories to all members of the repository's organization.

```polar theme={null}
actor User {}

resource Organization {
  roles = ["member", "admin"];
  permissions = ["set_default_role"];

  "set_default_role" if "admin";
}

resource Repository {
  roles = ["reader", "editor", "admin"];
  permissions = ["write"];
  relations = { organization: Organization };

  "write" if "editor";
}

has_role(actor: Actor, role: String, repo: Repository) if
  org matches Organization and
  has_relation(repo, "organization", org) and
  has_default_role(org, role) and
  has_role(actor, "member", org);

test "default org role grants permission to org members" {
  setup {
    has_default_role(Organization{"acme"}, "editor");
    has_role(User{"alice"}, "member", Organization{"acme"});
    has_relation(Repository{"anvil"}, "organization", Organization{"acme"});
  }

  assert has_role(User{"alice"}, "editor", Repository{"anvil"});
  assert allow(User{"alice"}, "write", Repository{"anvil"});
}
```

The ACME organization decided "editor" should be the default role on their repositories. ACME members like Alice can write to all ACME repositories.

## Toggles

You can conditionally inherit roles by specifying attributes on the resource itself instead of on a related resource.

A common example is a toggle on the resource. For example, a setting that specifies if the resource is "protected" and restricts access accordingly.

### Implement the logic

Instead of inheriting all roles unconditionally (`role if role on "organization"`) or a default role on all repositories, only allow users to inherit roles on repositories that aren't marked as "protected".

```polar theme={null}
actor User { }

resource Organization {
  roles = ["admin", "member"];
  permissions = [
    "read", "add_member", "repository.create",
  ];

  # role hierarchy:
  # admins inherit all member permissions
  "member" if "admin";

  # organization level permissions
  "read" if "member";
  "add_member" if "admin";
  # permission to create a repository
  # in the organization
  "repository.create" if "admin";
}

resource Repository {
  permissions = ["read", "delete"];
  roles = ["member", "admin"];
  relations = {
    organization: Organization,
  };

  "admin" if "admin" on "organization";

  # admins inherit all member permissions
  "member" if "admin";

  "read" if "member";
  "delete" if "admin";
}

# like `role if role on "organization"`
# but with an additional condition `is_protected`
has_role(actor: Actor, role: String, repository: Repository) if
  not is_protected(repository) and
  org matches Organization and
  has_relation(repository, "organization", org) and
  has_role(actor, role, org);

test "organization members can only read repositories that are not protected" {
  setup {
    has_role(User{"alice"}, "member", Organization{"acme"});
    has_relation(Repository{"anvil"}, "organization", Organization{"acme"});
    has_relation(Repository{"bar"}, "organization", Organization{"acme"});
    is_protected(Repository{"bar"});
    has_relation(Repository{"foo"}, "organization", Organization{"acme"});
    is_protected(Repository{"foo"});
    # grant Alice explicit access to foo
    has_role(User{"alice"}, "member", Repository{"foo"});
  }

  assert has_role(User{"alice"}, "member", Repository{"anvil"});
  assert allow(User{"alice"}, "read", Repository{"anvil"});
  assert_not allow(User{"alice"}, "read", Repository{"bar"});
  assert allow(User{"alice"}, "read", Repository{"foo"});
}

test "org admins can unconditionally read and delete repositories" {
  setup {
    has_role(User{"alice"}, "admin", Organization{"acme"});
    has_relation(Repository{"anvil"}, "organization", Organization{"acme"});
    is_protected(Repository{"anvil"});
  }

  assert allow(User{"alice"}, "read", Repository{"anvil"});
  assert allow(User{"alice"}, "delete", Repository{"anvil"});
}
```

The tests cover four cases:

1. As an organization member, Alice can read unprotected repositories.
2. As an organization member, Alice can *not* read protected repositories.
3. As an organization member, Alice can read a protected repository *if* she's explicitly invited to it.
4. As an organization admin, Alice can read and delete all repositories regardless of protected status.

## Combine default roles and toggles

The two pieces of logic combine together perfectly:

```polar theme={null}
has_role(actor: Actor, role: String, repository: Repository) if
  not is_protected(repository) and
  org matches Organization and
  has_relation(repository, "organization", org) and
  has_default_role(org, role) and
  has_role(actor, "member", org);
```

This rule grants organization members the default repository role on all non-protected repositories.

## Next steps

Conditional roles enable advanced authorization patterns while minimizing fact management. Consider these approaches for your application:

* **Default roles** when you need organization-wide permissions with minimal data sync
* **Toggles** when resources need protection levels or feature flags
* **Combinations** when you need both default inheritance and conditional access

For more complex scenarios, explore [attribute-based access control patterns](/develop/policies/abac) or learn about [role hierarchies](/develop/policies/rbac).
