Skip to main content
Polar, via Oso Cloud, can evaluate data that are stored outside your policy. These are referred to as “facts” in Oso documentation. Whether a fact is written directly in the policy or stored externally, Polar applies the same logic during authorization. The difference affects environment mutability, query performance, and where evaluation occurs. For related documentation:

Fact construction

Facts stored as data follow these rules:
  • They must be unconditionally true, no if clauses.
  • Arguments must be either primitives (e.g. 3, "two") or object literals (e.g. User{"alice"}).
Example:
integer_string_eq(2, "two");

Type inference

Oso infers the expected types of facts based on their usage in policy rules. For example:
has_permission(user: User, "pet", dog: Dog) if are_friends(user, dog);
From this rule, Oso infers that valid are_friends facts must take two arguments: a User and a Dog. Based on inferred types, Oso will:
  • Reject facts with mismatched types (e.g.,are_friends(User:alice, Rabbit:peter))
  • Reject facts with missing arguments (e.g., are_friends(User:alice))
  • Reject facts with unrecognized predicates (e.g., ar_frens(User:alice, Dog:fido))

Declaring unused fact types

If you want to store facts that aren’t currently used in your policy—e.g., tagging users or resources—you must declare the allowed type signature using declare:
declare has_tag(User, Tag);
This allows facts like has_tag(User:alice, Tag:is-cool), even if the policy does not use this fact type. You can declare the same fact with different argument types using multiple declare statements:
declare has_tag(User, Tag);
declare has_tag(Dog, Tag);
declare has_tag(Tag, Tag, Tag);
These declare statements form a union type. Oso will accept any fact that matches one of the declared or inferred types. You do not need to use declare for fact types already referenced in your policy, its only required for types your policy does not use. Most policies do not require any declarations.