oso helps developers build authorization into their applications. If you’ve never used oso before and want to get up-and-running quickly, this guide is for you.
In general, it takes less than 5 minutes to add oso to an existing application and begin writing an authorization policy.
In this guide, we’re going to add oso to our project, write our first policy, create a simple web server with no authorization, and write some rules for it. We encourage you to code along in your local environment!
Our application serves data about expenses submitted by users.
To start with, we have a simple
Expense class, and some stored data in the
We’ll need our application to be able to control who has access to this data. Before we add a web server and start making some requests, lets see if we can get some basic authorization in place!
In order to write our first authorization policy, we first need to add oso to our application. If you don’t already have it installed, go ahead and do so now:
Now that we’ve installed oso, let’s see how to make some basic authorization decisions.
Oso instance exposes a method to evaluate
allow rules that takes three arguments, actor, action, and resource:
The above method call returns
true if the actor
"firstname.lastname@example.org" may perform the action
"GET" on the resource
EXPENSES. We’re using
"GET" here to match up with the HTTP verb used in our server, but this could be anything.
For more on actors, actions, and resources, check out Glossary.
oso’s authorization system is deny-by-default. Since we haven’t yet written any policy code, Alice is not allowed to view expenses. To see that in action, start a REPL session and follow along:
Each time you load a file, it will load the policy without clearing previously loaded rules. Be sure to clear oso using the
clear method or create a new instance if you want to try adding a few new rules.
When we ask oso for a policy decision via
allow, 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 as the actor,
"GET" as the action, and
EXPENSE as the resource, satisfying the
allow("email@example.com", "GET", _expense); rule. When we pass in
"firstname.lastname@example.org" as the actor, the rule no longer succeeds because the string
"email@example.com" does not match the string
Authorizing HTTP Requests¶
Now that we are confident we can control access to our expense data, let’s see what it would look like in a web server. Our web server contains some simple logic to filter out bad requests and not much else.
In lieu of setting up real identity and authentication systems, we’ll use a custom HTTP header to indicate that a request is “authenticated” as a particular user. The header value will be an email address, e.g.,
"firstname.lastname@example.org". We’ll pass it to
allow as the actor and we’ll use the HTTP method as the action.
Finally, the resource is the expense retrieved from our stored expenses.
Here is the code for our web server. The highlighted lines show where we added oso:
If the request path matches the form
:id is the ID of an existing expense, we respond with the expense data. Otherwise, we return
Let’s use cURL to check that everything’s working. We’ll first start our server…
…and then, in another terminal, we can test everything works by making some requests:
$ curl -H "user: email@example.com" localhost:5050/expenses/1 Expense(amount=500, description='coffee', firstname.lastname@example.org') $ curl -H "user: email@example.com" localhost:5050/expenses/1 Not Authorized!
If you aren’t seeing the same thing, make sure you created your policy correctly in
Rules Over Dynamic Data¶
It’s nice that Alice can view expenses, but it would be really onerous if we had to write a separate rule for every single actor we wanted to authorize. Luckily, we don’t!
Let’s replace our static rule checking that the provided email matches
"firstname.lastname@example.org" with a dynamic one that checks that the provided email ends in
"@example.com". That way, everyone at Example.com, Inc. will be able to view expenses, but no one outside the company will be able to:
Once we’ve added our new dynamic rule and restarted the web server, every user with an
@example.com email should be allowed to view any expense:
$ curl -H "user: email@example.com" localhost:5050/expenses/1 Expense(...)
If a user’s email doesn’t end in
"@example.com", the rule fails, and they are denied access:
$ curl -H "user: firstname.lastname@example.org" localhost:5050/expenses/1 Not Authorized!
Writing Authorization Policy Over Application Data¶
At this point, the higher-ups at Example.com, Inc. are still not satisfied with our access policy that allows all employees to see each other’s expenses. They would like us to modify the policy such that employees can only see their own expenses.
To accomplish that, we can replace our existing rule with:
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 the expense.
Now Alice can see her own expenses but not Bhavik’s:
$ curl -H "user: email@example.com" localhost:5050/expenses/1 Expense(...) $ curl -H "user: firstname.lastname@example.org" localhost:5050/expenses/3 Not Authorized!
$ curl -H "user: email@example.com" localhost:5050/expenses/1 Not Authorized! $ curl -H "user: firstname.lastname@example.org" localhost:5050/expenses/3 Expense(...)
We encourage you to play around with the current policy and experiment with adding your own rules!
For example, if you have
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:
allow(approver, "approve", expense) if approver = expense.submitted_by.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 approver?
Does the expense’s
amountfield contain a value less than $100.00?
For more on leveraging application data in an oso policy, check out Application Types.
We just went through a ton of stuff:
Setting up our app to enforce the policy decisions made by oso.
Writing authorization rules over static and dynamic application data.
Subscribe to our newsletter
Stay up to date with the latest features and updates to oso.