Oso in 5 minutes

Oso helps developers build authorization into their applications. If you’ve never used Oso before and want to see it in action, this guide is for you. We’re going to walk through how to use Oso to add authorization to a simple web server.

Try it!

To follow along, clone the Go sample app:

git clone https://github.com/osohq/oso-go-quickstart.git

Run the server

Our sample application serves data about expenses submitted by users. The sample application has three important files.

One file defines a simple Expense class and some sample data stored in a map.

A second file has our HTTP server code, where we have defined a route handler for GET requests to the path /expenses/:id. We’ve already added an authorization check using the Oso library to control access to expense resources.

The third file is the Oso policy file, expenses.polar, and is currently empty.

Try it!

Install the project dependencies, then run the server:

$ go get github.com/osohq/go-oso
installing requirements

$ go run quickstart.go
server running on port 5050

With the server running, open a second terminal and make a request using cURL:

$ curl localhost:5050/expenses/1
Not Authorized!

You’ll get a “Not Authorized!” response because we haven’t added any rules to our Oso policy (in expenses.polar), and Oso is deny-by-default.

Let’s start implementing our access control scheme by adding some rules to the Oso policy.

Adding our first rule

Oso rules are written in a declarative policy language called Polar. You can include any kind of rule in a policy, but the Oso library is designed to evaluate allow rules, which specify the conditions that allow an actor to perform an action on a resource.

Edit it!

In our policy file (expenses.polar), let’s add a rule that allows anyone with an email ending in "@example.com" to view all expenses:

expenses-01-go.polar
allow(actor: String, "GET", _expense: Expense) if
    actor.EndsWith("@example.com");

Note that the call to EndsWith is actually calling out to the EndsWith method . The actor value passed to Oso is a string, and Oso allows us to call methods on it.

The Expense and String terms following the colons in the head of the rule are specializers, patterns that control rule execution based on whether they match the supplied argument. This syntax ensures that the rule will only be evaluated when the actor is a string and the resource is an instance of the Expense class.

Try it!

Once we’ve added our new rule and restarted the web server, every user with an @example.com email should be allowed to view any expense:

$ curl -H "user: alice@example.com" localhost:5050/expenses/1
Expense(...)

Okay, so what just happened?

When we ask Oso for a policy decision via Oso.IsAllowed(), the Oso engine searches through its knowledge base to determine whether the provided actor, action, and resource satisfy any allow rules. In the above case, we passed in "alice@example.com" as the actor, "GET" as the action, and the Expense object with id=1 as the resource. Since "alice@example.com" ends with @example.com, our rule is satisfied, and Alice is allowed to view the requested expense.

Try it!

If a user’s email doesn’t end in "@example.com", the rule fails, and they are denied access:

$ curl -H "user: alice@foo.com" localhost:5050/expenses/1
Not Authorized!

If you aren’t seeing the same thing, make sure you created your policy correctly in expenses.polar.

Using application data

We now have some basic access control in place, but we can do better. Currently, anyone with an email ending in @example.com can see all expenses — including expenses submitted by others.

Edit it!

Let’s modify our existing rule such that users can only see their own expenses:

expenses-02-go.polar
allow(actor: String, "GET", expense: Expense) if
    expense.SubmittedBy = actor;

Behind the scenes, Oso looks up the submitted_by field on the provided Expense instance and compares that value against the provided actor. And just like that, an actor can only see an expense if they submitted it!

Try it!

Alice can see her own expenses but not Bhavik’s:

$ curl -H "user: alice@example.com" localhost:5050/expenses/1
Expense(...)
$ curl -H "user: alice@example.com" localhost:5050/expenses/3
Not Authorized!
$ curl -H "user: alice@example.com" localhost:5050/expenses/3
Not Authorized!

Feel free to play around with the current policy and experiment with adding your own rules!

For example, if you have Expense and User classes defined in your application, you could write a policy rule in Oso that says a User may "approve" an Expense if they manage the User who submitted the expense and the expense’s amount is less than $100.00:

expenses.polar
allow(approver: User, "approve", expense: Expense) if
    approver = expense.SubmittedBy.Manager
    and expense.Amount < 10000;

In the process of evaluating that rule, the Oso engine would call back into the application in order to make determinations that rely on application data, such as:

  • Which user submitted the expense in question?
  • Who is their manager?
  • Is their manager the user who’s attempting to approve the expense?
  • Does the expense’s amount field contain a value less than $100.00?

For more on leveraging application data in an Oso policy, check out Application Types.

Want to talk it through?

If you have any questions, are getting stuck, or just want to talk something through, jump into Slack and an engineer from the core team (or one of the hundreds of developers in the growing community) will help you out.

What's next

Tell our engineers what it's like