Skip to main content
Authorization for resource creation presents a classic challenge: how do you authorize users to create resources when authorization typically depends on permissions granted after those resources exist? The solution depends on your resource hierarchy: This guide demonstrates both RBAC and ReBAC patterns for resource creation.

Bootstrapping root-level resources

Most Polar policies center around a root-level resource that serves as the foundation for all other resources:
  • Multi-tenant SaaS applications: resource Organization
  • Consumer applications: actor User
All other resources are defined in relation to this root-level resource. You need to provide an authorization path to create these root-level resources, which we call “boostrapping” authorization.

Use the global block

Create a global block that allows specific roles to create root-level resources.
actor User { }

global {
  roles = ["admin"];
  permissions = ["create_org"];

  "create_org" if "admin";
}

resource Organization {}

test "global admins can create Organizations" {
  setup {
    has_role(User{"alice"}, "admin");
  }

  assert allow(User{"alice"}, "create_org");
}
This policy creates a global admin role with create_org permission. Global admins can create organizations even when no other resources exist. Next, seed your authorization facts with data providing some users the global role you defined. Typically, this will be a user of your team who should have privileges elevated beyond most other users. For example, the above policy would require data like:
has_role(User{"alice"}, "admin")
The absence of the third argument is used as a convention to refer to global roles. In your application, use the explicit authorization API, akin to the CLI command. For example, you would authorize requests using the above policy and authorization data through the CLI using:
oso-cloud authorize User:alice create_org

Parent-child resources

Another common pattern for authorizing resource creation is to check the parent resource’s permissions.
actor User {}

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

  "repository.create" if "member";
  "read" if "member";
}

resource Repository {
  relations = { organization: Organization };
}

test "members can create repositories" {
  setup {
    has_role(User{"alice"}, "member", Organization{"acme"});
  }

  assert allow(User{"alice"}, "repository.create", Organization{"acme"});
}
The Repository resource doesn’t define its own roles. It inherits permissions from its parent Organization through the parent relation.

Further resources