What is Oso Cloud?

Oso Cloud is Distributed Authorization. It helps you model common authorization patterns, test your configuration, and check authorization decisions at runtime. It lets you choose how you manage your authorization data. You can centralize common authorization data (like roles) in Oso Cloud, while keeping service-specific data (like relationships between resources) in your application database. This lets Oso Cloud apply your application data to authorization decisions without requiring brittle synchronization and reconciliation mechanisms.

Concretely, it consists of the following components:

  1. Polar, our declarative configuration language for modeling authorization logic.

  2. Facts, a concise, expressive data format that is optimized for representing authorization entities and performing authorization queries.

  3. Oso Cloud, the service (built in Rust 🦀), which hosts your authorization logic and stores common facts that you need to share across multiple services (like roles). Oso Cloud responds to permission checks and related questions over an HTTP API. Our servers are replicated globally for <10ms latency and >99.99% uptime.

  4. Workbench, a visual rules editor for describing who’s allowed to do what in your app. Under the hood, this is fully extensible and backed by Polar.

  5. Clients for Node.js, Python, Go, Ruby, .NET, Java

  6. Tools to give you short and tight feedback loops, like a VS Code extension, unit tests, a debugger, and logging.

This document explains how Oso Cloud works, answering questions like:

  • What types of questions can your applications ask Oso Cloud?
  • Where does Oso Cloud fit into your infrastructure?
  • How does Oso Cloud store data about resources in your applications?
  • How does Oso Cloud use permissions and resource data to make access decisions?
  • How should your applications insert and update data in Oso Cloud?

What questions can Oso Cloud answer?

Many authorization questions take the form of simple permission checks. Oso Cloud can reliably respond to queries like “can user X perform action Y on resource Z?” in less than 10ms (excluding network latency).

Though permission checks are the core of an authorization service, Oso Cloud can answer more than just yes/no questions. Oso Cloud provides several other authorization APIs that let you answer questions like:

  • What are all of the resources that User X can perform action Y on?
  • What are all of the actions that User X can perform on resource Z?
  • What are all of User X’s roles on any organization?
  • What groups is User X a member of?

...and just about any other question you can think of.

Where does Oso Cloud fit into your infrastructure?

Oso Cloud is a managed service, meaning that Oso, Inc. runs it for you – we handle deployment, upgrades, and maintenance. Your applications talk to Oso Cloud over an HTTP API to perform authorization checks, query authorization-related data, or make changes to data stored in Oso Cloud. While your apps can communicate directly with the HTTP endpoints, we also provide wrapper clients (currently in Node, Python, Go, and Ruby).

Basic Architecture of Oso Cloud: Your Apps all talk to Oso Cloud over an HTTP API

Because just about every user action requires at least one authorization check, minimizing latency for an authorization service is crucial — production deployments of Oso Cloud are deployed in regions close to your infrastructure to keep latency low (<20ms total).

How does Oso Cloud store data?

In order to provide reliably fast answers to authorization checks, Oso Cloud stores data that is relevant to authorization. Oso represents data as facts that describe relationships between objects in your applications. Facts have a name and up to 5 arguments (they look a bit like function calls). The vast majority of facts will have 1-3 arguments. Some examples of facts in a GitHub-style application are:

  • Bob can explicitly edit the "docs" repo: has_permission(User{"bob"}, "edit", Repository{"docs"}).
  • Bob is an owner of the Acme organization: has_role(User{"bob"}, "owner", Organization{"acme"}).
  • The Anvils repository belongs to the Acme organization: has_parent(Repository{"anvils"}, Organization{"acme"}).
  • The Oso repository is public: is_public(Repository{"oso"}).

Because it can be cumbersome to convert all authorization-relevant data to facts and synchronize it to Oso Cloud, Oso allows you to use application data from your local databases in authorization decisions. Rather than sending this data as facts to Oso Cloud, you supply a configuration file to the Oso Cloud client that tells it how to convert your local data to facts at authorization time. We call this Distributed Authorization, and you can use it to apply your local application data to individual decisions or to lists of authorized resources.

Extending your data with a policy

Without a way to write logic over your data, you’d have to insert a single has_permission fact for every single (Actor, Action, Resource) combination that might be allowed in your apps — a combinatorial explosion that would quickly get out of hand!

Writing a policy allows you to derive permissions from other data (like roles, relationships, and attributes). Oso Cloud stores your policy (written in the Polar language) alongside your data and uses it to make access decisions.

A policy consists of rules that extend your facts. Oso Cloud uses the rules in your policy to infer other facts about your data. Some examples of rules that you might write in a policy for a GitHub-style application:

Any user that has a reader role on a repository can perform the read action.

has_permission(user: User, "read", repo: Repo) if
has_role(user, "reader", repo);

A user that has an owner role on a organization inherits an reader role on any repository belonging to that organization.

has_role(user: User, "reader", repo: Repo) if
has_role(user, "owner", org) and
has_parent(repo, org);

Any user can perform the read action on a public repository.

has_permission(_: User, "read", repo: Repo) if


Want to learn more about writing Polar rules? Check out the Polar syntax guide.

How does Oso Cloud answer authorization questions?

When your application asks an authorization question, like "can User:1 read Org:1?", Oso Cloud uses your policy and facts to determine whether there is a match for has_permission(User:1, "read", Org:1):

Oso Cloud answers authorization questions using your Polar policy and your facts.

Under the hood, Oso Cloud queries the Polar policy engine to determine all of the combinations of facts that would need to exist for the actor to have that particular permission — in other words, all of the ways that the actor might have that permission. Then it queries your facts to check if the actor actually has the facts that would grant the permission in any of those ways. If there is a match, Oso Cloud records why that match occurred along with the data that supported the decision, so that all decisions are auditable. Oso Cloud handles the complexity of indexing your facts so that these checks can happen efficiently.

If you're using Distributed Authorization to keep some of your authorization data in your local application databases, then Oso Cloud returns a partially evaluated response to the Oso Cloud client in your application. This response includes information about the facts that have to be resolved from your local application data. The Oso Cloud client then uses the information in oso.yaml to query your local database and complete the evaluation of the response to the authorization question.

Inserting facts into Oso Cloud

Oso Cloud exposes a fact management API with HTTP endpoints that let you create and delete facts. Your applications call these APIs on any user action that changes authorization-related data. Oso Cloud provides clients in Node, Python, Go, and Ruby to wrap the HTTP APIs, but you can also use the HTTP API directly to update data in Oso Cloud from any application.

Some examples of scenarios where a GitHub-style application might insert or delete facts:

  • When an admin invites a collaborator to a repository, the app inserts a has_role fact, like has_role(User{"some_coder"}, "collaborator", Repo{"anvils"}).
  • When a repository is created, the app inserts a has_parent fact, like has_parent(Repo{"anvils"}, Org{"acme"}).
  • When a user leaves an organization, the app deletes the has_role fact linking them with that organization.

In situations where it doesn't make sense to store all authorization data in Oso Cloud, you can also send context facts at authorization time. For more details, read more about context facts.

Ready to get started?

Talk to an Oso Engineer

If you'd like to learn more about using Oso Cloud in your app or have any questions about this guide, connect with us on Slack. We're happy to help.

Get started with Oso Cloud →