Implement the logic in Oso Cloud
Now you'll implement the authorization logic in Oso Cloud. You'll run the Oso Cloud logic alongside your existing logic to confirm that the Oso Cloud implementation is correct before you replace the original code.
Convert the logic to Polar
In Oso Cloud, you express your application's authorization logic in Polar. Polar is a concise and flexible language that provides powerful abstractions for both authorization models and application entities. But for now, you'll implement the logic with simple permission checks in order to mirror the existing application logic. Once that works, you can improve the logic by adding the appropriate abstractions.
Recall the authorization logic from the previous step:
This says that a user has the read permission on a repository if:
- they have a role on the repository or
- they have a role on the repository's parent organization
Let's write this logic in Polar:
An in-depth treatment of Polar is beyond the scope of this walkthrough, but there are a couple of things that are worth highlighting above:
- You declare the entities that are involved in authorization logic as actors or resources.
- An actor is the entity that is requesting a permission (e.g.
User
) - A resource is the entity upon which the actor is requesting the permission (e.g.
Organization
,Repository
)
- An actor is the entity that is requesting a permission (e.g.
- There are two
has_permission
statements that mirror the logic from our application.
Copy the Polar above and save it to your personal Oso Cloud Workspace (opens in a new tab) (you set this up in the quickstart).
Use the Oso Cloud SDK alongside the existing authorization code
Next, you'll use the Oso Cloud SDK to evaluate authorization requests in your application. Don't replace your existing logic immediately, though. Instead, add the check API call for your language alongside your existing logic so that you can compare the results. In TypeScript, this is authorize()
First, import and instantiate the Oso Cloud client.
Then, add the authorize()
call to the canReadRepo()
function, alongside the existing logic.
The call to osoClient.authorize() in the following sample will not return the correct results until you send data to Oso Cloud in the next step. Don't use it in live environments without providing data.
The authorize()
function accepts three arguments: an actor, an action, and a resource. It returns true
if the actor has permission to perform the action on the resource and false
otherwise.
- The
actor
andresource
arguments are represented by atype
and anid
.- This is how Oso represents entities in your application in the general case.
- In the Node SDK, these entities take the form of an object with
type
andid
properties.User
object:{type: "User", id: user.id.toString() }
Repository
object:{type: "Repository", id: repo.id.toString() }
- The
permission
argument is a string that contains the name of the permission."read"
In the sample above, the User
and Repository
objects are assigned to the osoUser
and osoRepository
variables, respectively. This simplifies the resulting osoClient.authorize()
call.
If you're using a different client library, the form of the actor
and
resource
arguments will be different. Check the documentation for your
language's client for details.
Compare the results from Oso Cloud to the original code
By writing the results of the original code and the Oso Cloud SDK to a log, you can compare them to make sure that the results are the same before you switch to using Oso for live authorization. If you compare those results now, you'll see something like this:
backend | User:1 read Repository:1: inline: false; Oso: falsebackend | User:1 read Repository:2: inline: true; Oso: falsebackend | User:1 read Repository:3: inline: false; Oso: falsebackend | User:1 read Repository:4: inline: false; Oso: falsebackend | User:1 read Repository:5: inline: false; Oso: falsebackend | User:1 read Repository:6: inline: true; Oso: falsebackend | User:1 read Repository:7: inline: false; Oso: false
The calls to Oso always return false
, even when the original code returns true
. That's because Oso doesn't yet know which users have which roles, or which repositories belong to which organizations. To make that happen, you need to send data to Oso Cloud.