Facts as Data

Polar facts as data

Polar, powered by Oso Cloud, can consider facts stored outside your policy when making authorization decisions. In Oso, this is often referred to as "data."

It's important to note that storing facts as data does not necessarily have semantic meaning when making authorization decisions; if you stored the facts as data or within your policy, the decisions Polar makes would be the same.

Instead, choosing to store facts as data impacts secondary features like the mutability of your environment, performance, and where authorization decisions ultimately occur. For more details about those considerations, see:


Facts stored as data have a construction similar to generic rules, but:

  • They must be unconditionally true, i.e. they cannot have an if clause after defining their parameters.
  • All parameter values must be primitive values (e.g. 3) or object literals (e.g. User{"alice"}).

For example, the following fact could be stored as data:

integer_string_eq(2, "two");


Where you store facts and how you manage them is a concern of Oso Cloud, moreso than of Polar. For more detail, see Facts: the Oso Cloud Data Model, specifically the following sections:

Type inference

Oso infers type information about facts based on how the facts are used in your policy. For example, with a policy like this:

has_permission(user: User, "pet", dog: Dog) if are_friends(user, dog);

Oso infers that it should only accept are_friends facts with two arguments, where the first argument is a User and the second is a Dog.

Oso uses these inferred fact types to prevent you from inserting invalid facts. For example, with the above policy, if you attempted to tell Oso the fact are_friends(User:alice, Rabbit:peter), Oso would reject the fact, because your policy doesn't use facts with the type are_friends(User, Rabbit). Additionally, Oso prevents you from accidentally omitting an argument – Oso will reject are_friends(User:alice), because the second Dog argument is missing.

Oso also uses these inferred types to prevent you from inserting facts that it doesn't know about. This makes it impossible to accidentally insert a fact with a misspelled predicate, like ar_frens(User:alice, Dog:fido).

Overriding inferred types

What if you want Oso Cloud to store a fact that isn't used anywhere in your policy? For instance, maybe you want to tag users by inserting has_tag facts into Oso, anticipating that you might use tags in your policy someday. Or maybe you already tag users and use those in your policy, but you want to start tagging organizations, too.

In these cases, you can use the declare statement to force Oso to accept a certain fact type:

declare has_tag(User, Tag);

This will make Oso accept facts like has_tag(User:alice, Tag:is-cool), even if your policy doesn't currently use facts like this.

You can have multiple declare statements for a given fact predicate:

declare has_tag(User, Tag);
declare has_tag(Dog, Tag);
declare has_tag(Tag, Tag, Tag); # I heard you like tags.

These declare statements form a union type-- as long as a fact matches one of the declared or inferred types, Oso will accept it.

You never need to use a declare statement for fact types that are used in your policy. declare statements are only for making Oso accept fact types that your policy never uses. Most policies will not use declare statements.

Up next

Talk to an Oso Engineer

If you want to learn more about Polar, schedule a 1x1 with an Oso engineer. We're happy to help.

Get started with Oso Cloud →