Get Started
/
Add Oso Cloud to Your App

Add Oso Cloud to Your App

Before going through this guide, make sure you follow the Oso Cloud Quickstart to get your Oso API Key properly set in your environment.

This guide will show you how you can use the Oso Cloud client libraries to perform authorization checks in your app.

Prerequisites

If you've finished the quickstart, you should have an Oso Cloud API Key and a policy that looks like this:

actor User {}

resource Organization {
  permissions = ["read"];
  roles = ["owner"];

  "read" if "owner";
}

resource Repository {
  permissions = ["push"];
  roles = ["maintainer"];
  relations = { parent: Organization };

  "maintainer" if "owner" on "parent";
  "push" if "maintainer";
}

Constructing an Oso instance

The Oso Cloud libraries work by providing an Oso class which you configure with your Oso Cloud URL and API key:

PythonGoNode
from oso_cloud import Oso

oso = Oso(url="https://cloud.osohq.com", api_key=YOUR_API_KEY)

Under the hood, this class wraps an HTTP API and handles converting your application objects to and from json.

Enforcement in a controller

In the quickstart, you used the Oso Cloud CLI to perform authorization checks like this:

$ oso-cloud authorize User:bob read Organization:acme

You can use the Oso class to perform the same check in your application. For example, you can check whether a user has the "read" permission on an organization whenever they make a GET request for that organization:

PythonGoNode
@app.route("/orgs/<org_id>")
def show_org(org_id):
    # get the `Organization` 
    org = db.get_org(org_id)
    # get the authenticated user making the request
    current_user = get_current_user()
    if oso.authorize(current_user, "read", org):
      # Action is allowed
      return f"<h1>An Organization</h1><p>Welcome to organization {org.name}</p>", 200
    else: 
      return "<h1>Whoops!</h1><p>That organization was not found</p>", 404

Now, when Bob views the /orgs/acme endpoint, your application asks Oso Cloud to perform the exact same check you did in the quickstart and only shows him the page if he's authorized to read on the Acme organization.

💡

In Oso, objects are represented as a Type:ID combination. Each Oso Cloud client library uses a bit of logic to determine the type and ID for a particular object passed into the authorize() method. For more information, check out the reference docs for Python, Node, or Go.

Updating data

In your policy above, there is a Repository type that is owned by the Organization type. A user can read from and push to repositories that belong to their organizations. For this to work, your application needs some way of telling Oso Cloud which repositories belong to which organizations.

In the CLI, you could do this using oso-cloud tell has_relation:

$ oso-cloud tell has_relation Repository:anvils parent Organization:acme

Your application can use the Oso class to do this whenever a user creates a new Repository (in this case, via a POST request):

PythonGoNode
@app.route("/orgs/<org_id>/repos", methods = ['POST'])
def create_repo(org_id):
  # get the `Organization` 
  org = db.get_org(org_id)
  # get the authenticated user making the request
  current_user = get_current_user()
  repo = Repository(name=payload.get("name"), parent_org=org)
  db.add_repo(repo)
  oso.tell("has_relation", repo, "parent", org)
  return f"<h1>Success!</h1><p>Added repository {repo.name} to organization {org.name}</p>", 200

Now, when someone creates a new repository with the /orgs/acme/repos endpoint, your application will tell Oso Cloud that Organization:acme is that repository's parent. This means that Bob (and any other owners of the Acme organization) will be authorized to push to this repository.

Putting all it together

A more realistic version of the "add a new repository" endpoint will probably check if a user is authorized to create repositories on that organization. To enable this, you need to add a create_repo permission to the Organization declaration in your policy:

actor User {}

resource Organization {
  # add a new `create_repo` permission
  permissions = ["read", "create_repo"];
  roles = ["owner"];

  "read" if "owner";
  # grant `create_repo` owners 
  "create_repo" if "owner";
}

resource Repository {
  permissions = ["push"];
  roles = ["maintainer"];
  relations = { parent: Organization };

  "maintainer" if "owner" on "parent";
  "push" if "maintainer";
}

Now the "add a new repository" endpoint can perform authorization and update data in Oso Cloud:

PythonGoNode
@app.route("/orgs/<org_id>/repos", methods = ['POST'])
def create_repo(org_id):
  # get the `Organization` 
  org = db.get_org(org_id)
  # get the authenticated user making the request
  current_user = get_current_user()
  # check that the user can create repositories
  if oso.authorize(current_user, "create_repo", org):
    repo = Repository(name=payload.get("name"), parent_org=org)
    db.add_repo(repo)
    oso.tell("has_relation", repo, "parent", org)
    return f"<h1>Success!</h1><p>Added repository {repo.name} to organization {org.name}</p>", 200
  else: 
    return "<h1>Whoops!</h1><p>That organization was not found</p>", 404

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 →