How Oso Cloud Works

How Oso Cloud Works

Oso Cloud is a managed authorization service. It lets you model common authorization patterns, store authorization-relevant data, and respond to all authorization questions from any of your apps.

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

  • Where does Oso Cloud fit into your infrastructure?
  • What types of questions can your applications ask Oso Cloud?
  • 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?

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 libraries (currently in Go, Python, and Node).

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, 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).

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 actions that User X can perform on resource Y?
  • What are all of User X’s roles on any organization?
  • What groups is User X a member of?

How does Oso Cloud store data?

In order to provide reliably fast answers to authorization checks, Oso Cloud stores all data that might be relevant to authorization. Oso stores data as facts that describe relationships between objects in your applications. Facts have a name and arguments (they look a bit like function calls). 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).

Facts in Oso Cloud can refer to objects in your application using a type+ID combination, like User:abc. A resource in your application should be uniquely identifiable by its type and ID.

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 an application asks an authorization question, like can User:1 read Org:1?, Oso Cloud uses the policy and the 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 ways that the actor might have that particular permission. Then it queries your facts to check if the actor actually has 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.

Inserting facts into Oso Cloud

Oso Cloud exposes a management API with two HTTP endpoints: create fact and delete fact. Your applications call these APIs on any user action that changes authorization-related data. Oso Cloud provides client libraries in Go, Node, and Python to wrap the HTTP APIs, but you can 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.

What data should you store in Oso Cloud?

The only data that you need in Oso Cloud is “authorization-relevant” data — data that is used in authorization decisions. In typical applications, authorization-relevant data takes the following forms (but could extend beyond this list):

  • Roles — who has been assigned which permissions? Roles are a basic type of authorization data for granting a set of permissions to different users.
  • Resource hierarchies — which resources are nested inside of other resources? In order to let permissions flow through the tree, the tree itself must be used during authorization decisions.
  • Creator/owner relationships — which user created this resource? If creators have special privileges on their resources, then this is authorization-relevant data.
  • Authorization attributes — is this resource publicly visible? Is this user banned? Sometimes an authorization decision depends on the attributes of a particular object.

You should insert into Oso Cloud any data that is relevant for an authorization decision so that authorization queries are fast.

Ready to get started?

Talk to an Oso Engineer

Our team is happy to help you get started with Oso. If you'd like to learn more about using Oso in your app or have any questions about this guide, schedule a 1x1 with an Oso engineer.

Get started with Oso Cloud →