Replace context facts with local authorization
Rather than converting your authorization data to facts and sending it to Oso with every authorization request, you can use Local Authorization to tell Oso how to construct a query that will let you fetch that data directly when you need it to resolve an authorization request. Setup requires two things:
- A configuration file that maps your facts to SQL queries
- Using the distributed check API in your application code
Write the configuration file
You configure Local Authorization by passing a yaml file to the Oso Cloud client when you instantiate it. This configuration file lists the fact signatures that you use for authorization queries and associates them with the SQL that generates the facts from your application data.
Recall that you send up to three context facts to Oso for any "read repository" authorization request:
has_relation(Repository: repoId, "parent", Organization: orgId) has_role(User: userId, role, Organization: orgId) has_role(User: userId, role, Repository: repoId)
These are the fact signatures that you'll include in the config file.
There are a few things to note:
- Any value that is returned by the query is represented in the fact signature by using the wildcard character (
_
). - Any value that is not returned from a query must be explicitly specified in the fact signature by its type and value (e.g.
String:parent
). - The
sql_types:
section is optional, but strongly recommended.
Use the distributed check API
Now you can provide this configuration file to the Oso Cloud client when you instantiate it and use the Distributed Check API to resolve authorization requests without passing the data as facts to Oso Cloud. In the Typescript SDK, this means that you'll use authorizeLocal
in place of authorize
.
The major changes are highlighted:
- The osoClient instantiation has been modified to include the
oso-data-bindings.yml
file. - The call to
authorize()
has been replaced with a call toauthorizeLocal()
- The query returned from
authorizeLocal()
is executed against the database to resolve the authorization request
You'll also notice that the canReadRepo()
function is noticeably smaller. This is because we don't need any code in that function to get role data and convert it to facts. That's all handled by the query returned from authorizeLocal()
now.
You can write the query that authorizeLocal()
returns to a log if you'd like
to inspect it.
Now let's confirm that the results from Oso Cloud are still correct.
backend | User:1 read Repository:1: inline: false; Oso: falsebackend | User:1 read Repository:2: inline: true; Oso: truebackend | 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: truebackend | User:1 read Repository:7: inline: false; Oso: falsebackend | User:1 read Repository:8: inline: false; Oso: falsebackend | User:1 read Repository:9: inline: false; Oso: falsebackend | User:1 read Repository:10: inline: false; Oso: false
Everything looks good! All that remains is to replace the original authorization logic with the Oso Cloud version.