Skip to main content
Facts are the data Oso Cloud uses to make authorization decisions. They represent your application’s authorization-relevant data — roles, relationships, attributes, or context — in a consistent, queryable format.

Understand how Oso uses facts

Every authorization decision in Oso combines:
  • Your policy (written in Polar): the logic that defines who can do what.
  • Facts: the current state of your application that the policy uses to decide.
When your application calls Oso Cloud to check access, Oso evaluates your policy and matches it against the facts available from:
  1. Centralized facts in Oso Cloud.
  2. Context facts sent with the request.
  3. Local facts queried from your application database (if using Local Authorization).
You can access facts during authorization checks in two ways:
  • Check API: performs authorization decisions using data stored in your centralized authorization data store. Available via CLI and SDKs for Node, Python, Go, Java, Ruby, and .NET.
  • Local Check API: performs checks using your local facts while still considering centralized authorization data. See Local Authorization for details.

Know the fact structure

A fact has:
  • Name (predicate) — usually in verb_object form for readability, e.g. has_role, has_relation, is_public.
  • Arguments — 1-5 arguments, each either:
    • A typed ID reference to an application object: User{"alice"}.
    • A literal value: "admin", 42.
Examples:
# Multitenant role
has_role(User{"alice"}, "admin", Organization{"acme"})

# Resource relationship
has_relation(Repository{"anvils"}, "organization", Organization{"acme"})

# Resource attribute
is_public(Repository{"roadmap"})

# Contextual data
has_pricing_tier(Organization{"acme"}, "hobby")

Choose where to store facts

Data TypeStorage Recommendation
Affects multiple servicesStore in Oso Cloud.
Single-service onlyKeep in your application DB.
Changes frequentlyKeep in your application DB.
High cardinality (e.g. millions of files)Keep in your application DB.
Global attributes (e.g. is_superadmin, is_banned)Store in Oso Cloud.
Ephemeral/request-specific (e.g. IP, time of day)Send as context facts.

Centralize shared facts in Oso Cloud

Centralized facts are optimized for authorization lookups and can be faster than application DB queries.

When to centralize

  • Organization/resource roles: has_role(User, "admin", Organization).
  • Global flags: is_superadmin(User), is_banned(User).

Manage facts with the API

ActionAPI NamesNotes
Transactionbatch, bulkAtomic inserts/deletes (recommended).
Writeinsert, tellAdd facts.
DeletedeleteRemove facts.
ReadgetFetch centralized facts (no inference).
SDKs: Node, Python, Go, Java, Ruby, .NET. See SDK references for full method signatures. CLI also supported (no transaction API).

Pass context facts for request-specific data

Context facts exist only for the duration of a request. Use them for:
  • External data (e.g. IDP token claims).
  • Ephemeral attributes (e.g. is_weekend, request_came_from_eu).
Pass them in your authorization request; syntax varies by SDK.

Reference facts in Polar policies

# Simple attribute check
has_permission(user: User, "read", repo: Repository) if
  is_public(repo);
# Derived fact
has_role(user: User, "admin", _: Organization) if
  is_superadmin(user);

Validate and declare fact types

Oso infers fact types from policy usage:
has_permission(user: User, "pet", dog: Dog) if
  are_friends(user, dog);
Only facts matching are_friends(User, Dog) will be accepted. Invalid facts (wrong type, missing args, misspelled predicates) are rejected. Declare unused types explicitly:
declare has_tag(User, Tag);

Keep facts in sync

Keep centralized facts in sync with your application database:
  • Insert: When adding roles, relationships, or attributes.
  • Delete: When removing them.
  • Bulk operations: For initial loads or periodic sync.
  • Use transactional APIs (batch, bulk) to apply multiple changes atomically.
Example (GitHub-style app):
  • Invite collaborator → insert has_role(User{"coder"}, "collaborator", Repo{"anvils"}).
  • User leaves org → delete has_role(User{"alice"}, "member", Org{"acme"}).

Facts in different authorization models

Facts can represent:
  • RBAC. Role assignments: has_role(User, "admin", Org).
  • ABAC. Attributes: has_department(User, "engineering").
  • ReBAC. Relationships: has_relation(Document, "folder", Folder).
You can combine these in a single policy.