The Polar Language in Oso Cloud

Oso Cloud uses the Polar programming language to express authorization logic and policies. When you view or edit your policy in the Rules Editor (opens in a new tab), you’re working with Polar. This guide is an introduction to the Polar language: what it is, how it works, why we've chosen to use it.

For a more complete guide to syntax, use our Syntax Guide.

Declarative Programming

Polar is a declarative programming language (opens in a new tab). It's very different from the imperative programming languages — like Python, JavaScript, or Go — that we often do our day-to-day work in.

In a declarative programming language, you state what your program should do, and the language runtime will compute it.

  • SQL is a declarative programming language: you state what records you'd like to fetch, and the SQL runtime determines what steps to take to return those records.
  • Regular expressions are a declarative language: you write what patterns you'd like to be matched, and it's up to the runtime to return the text that matches those patterns.

Polar is similar. You'll write authorization rules, query those rules, and Polar will tell you what your query matched. Working with Polar is much like working with a database. When writing code, you'll write information to your database. At runtime, you'll query that information.

Logic Programming

Polar is also a logic programming language (opens in a new tab). This means that it's designed to answer questions about a set of rules. You'll see how this works in the How Polar code executes section.

Advantages

  • Declarative languages like Polar are concise. This means more than just saving a few characters in typing your program. You can dramatically compress your program by making use of the language runtime. Being able to express your program concisely means simpler programs, fewer places to make mistakes, and less complexity when you're making changes.
  • Logic programming is very well-suited to the domain of authorization. Authorization queries like, "Is this user allowed access to this resource?" are easy to answer with a logic programming language.

Caveats

  • It takes practice to read Polar code. If you've used regular expressions extensively, you know that it takes some practice to look at a regular expression and see what it does. Polar is similar — at first, it looks like Polar statements aren't doing much. That's because the language runtime handles so much for us.
  • Polar executes in a way that might be unfamiliar to you. It runs very differently from how most app code executes. That's why we have these guides—we'll help you get fluent in Polar!

How Polar code executes

ℹ️

For the next few examples, we'll use only the base language, without touching authorization just yet.

Here's one Polar rule.


father("SisterBear", "PapaBear");

In words, this line means "father is true when it's called on the strings "SisterBear" and "PapaBear"." This short example defines a rule named father. It does this without an explicit definition step! No need to write def father():.

We can add another rule:


father("SisterBear", "PapaBear");
father("BrotherBear", "PapaBear");

These lines mean:

  • "father is true when it's called on the strings "SisterBear" and "PapaBear"."
  • "father is also true when it's called on the strings "BrotherBear" and "PapaBear"."

Notice that these rules exist side-by-side. We can have any number of rules that use the father predicate — adding a new rule is much like adding a new database entry.

Now that we have some rules, we can add them to Oso Cloud and query them with the Oso Cloud CLI.

Querying Polar from Oso Cloud

ℹ️

In the following steps, you’ll create an Oso Cloud account and configure your local environment to work with it.

Adding the Rules to Oso Cloud

First, let’s add our rules to Oso Cloud. You can create a free Oso Cloud account by logging in with Google or GitHub at ui.osohq.com (opens in a new tab). Once you’ve created your account:


father("SisterBear", "PapaBear");
father("BrotherBear", "PapaBear");

  • Click the “Deploy” button

Now that you’ve added the rules to Oso Cloud, let’s set up your local environment to query them.

Configuring your Local Environment

To query these rules from your local system, you’ll need to generate an API key and install the oso-cloud CLI. We’ll do that now.

  • Navigate to the API Keys tab (opens in a new tab) under “Organization Settings.”
  • Create a new API Key in your current environment.
  • Set the Access Level to “Read Only” when prompted.
  • Save the key somewhere safe. You’ll need it later when we configure your local environment.
  • Navigate to the CLI tab (opens in a new tab) under “Install.” Follow the instructions on the page to install and configure the CLI.
  • Confirm that the CLI is installed and configured for your Oso Cloud environment by entering the following command in your terminal.

    $ oso-cloud policy

  • If your environment is configured correctly, you’ll see the rules we entered in the Rules Editor.

    $ oso-cloud policy
    == Policy: <no name> ==
    father("SisterBear", "PapaBear");
    father("BrotherBear", "PapaBear");

Now that your environment is set up, we can use the oso-cloud CLI to work with Polar.

Working with Polar Rules

We can ask Oso Cloud if, given the current set of rules, it knows whether SisterBear’s father is PapaBear:


$ oso-cloud query father "SisterBear" "PapaBear"
father(String:SisterBear, String:PapaBear)

We asked a question about the current set of rules, and got an answer. In Oso Cloud, this answer is expressed as a fact. For a thorough treatment of facts, see Facts: The Oso Cloud Data Model. For now, it’s enough to know that the expression father(String:SisterBear, String:PapaBear) means that Oso Cloud knows that SisterBear’s father is PapaBear.

💡

If you’re familiar with logic programming, then this statement is equivalent to “the predicate father holds for the arguments "SisterBear" and "PapaBear".

We told Oso Cloud that SisterBear’s father is PapaBear, but we didn’t tell it that PapaBear’s father is SisterBear. So, if we ask Oso Cloud if PapaBear’s father is SisterBear, we get back no results:


$ oso-cloud query father "PapaBear" "SisterBear"
(no results)

Note that the order of the arguments matters. It must be the same as their order in the rule. This allows us to express relationships in a concise way: PapaBear is the father of SisterBear, but SisterBear is not the father of PapaBear.

Let's ask a more open-ended question.


$ oso-cloud query father _ "PapaBear"
father(String:BrotherBear, String:PapaBear)
father(String:SisterBear, String:PapaBear)

This asks, "what are all the values _, for which father(_, "PapaBear") is true?" When querying Oso Cloud via the CLI, the _ character is called a wildcard. We can use a wildcard in a query to return all the values that make the query true. And we get exactly that as our answer: _ could be either "SisterBear" or "BrotherBear".

Conditional rules

So far, we've seen rules that are unconditionally true. We can also write rules that are conditionally true. Here's one:


grandfather(grandchild: String, grandparent: String) if
parent matches String and
father(grandchild, parent) and
father(parent, grandparent);

Note that in a rule, we can use variables like grandchild, grandparent, and parent. We’ll get warnings from Oso Cloud if we don’t tell it what type a variable is, so we add annotations such as grandchild: String and parent matches String so the types of all our variables are explicit.

To use this rule effectively, we'll need one more father rule.


father("PapaBear", "GrandpaBear");

Copy the new rules and paste them into the Oso Cloud Rules Editor (opens in a new tab), then re-deploy your Policy. When you’re all done, your policy should look like this.


father("SisterBear", "PapaBear");
father("BrotherBear", "PapaBear");
father("PapaBear", "GrandpaBear");
grandfather(grandchild: String, grandparent: String) if
parent matches String and
father(grandchild, parent) and
father(parent, grandparent);

Now, we can ask Oso Cloud questions about this rule.


$ oso-cloud query grandfather "SisterBear" _
grandfather(String:SisterBear, String:GrandpaBear)

Oso Cloud has deduced the grandfather of SisterBear!

Most Polar rules you'll see are in the same statement if condition; form as the grandfather rule we just wrote. That's where we'll wrap up this guide — to dive deeper into Polar syntax, we have a Polar Syntax Guide.

We haven’t covered how to use Polar to express particular authorization policies. Many Polar examples can be found in our authorization guides.

Talk to an Oso Engineer

If you have any questions about this guide, or would like to learn more about Polar, schedule a 1x1 with an Oso engineer. We're happy to help.

Get started with Oso Cloud →