DotNet Client API
Before going through this guide, make sure you follow the Oso Cloud Quickstart to get your Oso Cloud API Key properly set in your environment.
First, install the OsoCloud
package:
dotnet add package OsoCloud
Instantiating an Oso Cloud client
The Oso Cloud client provides an Oso
class
using OsoCloud;var oso = new Oso("https://api.osohq.com", YOUR_API_KEY);// Later:await oso.Tell("has_role", new List<Value> { user, role, resource});// Wherever authorization needs to be performed:var allowed = await oso.Authorize(user, action, resource);if (allowed) { // Action is allowed.}
You should instantiate one client and share it across your application. Under the hood, it reuses connections to avoid paying the cost of negotiating a new connection on every request.
Specifying an Oso Fallback host
If you have deployed Oso Fallback nodes to your infrastructure, you may specify the host when instantiating the Oso Cloud client.
// Assumes Oso Fallback is hosted at http://localhost:8080var oso = new Oso("https://api.osohq.com", YOUR_API_KEY, "http://localhost:8080");
Passing application entities into the client
Under the hood, Oso Cloud represents an entity in your application as a combination of a type and an ID, which together uniquely identify the entity.
The DotNet client represents these entities as oso.Value
objects with both Type
and Id
properties.
For example:
var alice = new oso.Value("User", "alice");anvilsRepository = new oso.Value("Repository", "anvils");
You will pass objects like these into nearly every function call you make to the DotNet client.
Centralized Authorization Data API
Oso Cloud clients provide an API to manage authorization data stored directly in Oso Cloud.
Add fact: oso.Tell(name, args)
Adds a fact named name
with the provided arguments. Example:
await oso.Tell(
"has_role",
new Value("User", "bob"),
new Value("String", "owner"),
new Value("Organization", "acme")
)
Add many facts: oso.BulkTell(facts)
For Oso Cloud developer accounts, BulkTell
, BulkDelete
, and Bulk
calls
are limited to 20 facts. If you attempt to send more than 20 facts, the CLI
will return an error.
Adds many facts at once. Example:as
oso.BulkTell(new List<Fact> { new oso.Fact{ "has_role", new List<Value>{ new oso.Value("User", "bob"), new oso.Value("String", "owner"), new oso.Value("Organization", "acme") } }, new oso.Fact{ "has_role", new List<Value>{ new oso.Value("User", "bob"), new oso.Value("String", "maintainer"), new oso.Value("Repository", "anvil") } }})
Delete fact: oso.Delete(name, args)
Deletes a fact. Does not throw an error if the fact is not found. Example:
oso.Delete( "has_role", new List<Value> { new oso.Value("User", "bob"), new oso.Value("String", "maintainer"), new oso.Value("Repository", "anvil") })
Delete many facts: oso.BulkDelete(facts)
Deletes many facts at once. Does not throw an error when some of the facts are not found. Example:
oso.BulkDelete(new List<Fact> { new oso.Fact{ "has_role", new List<Value> { new oso.Value("User", "bob"), new oso.Value("String", "owner"), new oso.Value("Organization", "acme") }, }, new oso.Fact{ "has_role", new List<Value> { new oso.Value("User", "bob"), new oso.Value("String", "maintainer"), new oso.Value("Repository", "anvil") }, },})
Transactionally delete and add facts: oso.Bulk(delete, tell)
Deletes and adds many facts in one atomic transaction. The deletions are performed before the adds. Does not throw an error when the facts to delete are not found. Example:
oso.Bulk(new List<Fact> { new oso.Fact{ "has_role", new List<Value> { new oso.Value("User", "bob"), new oso.Value("String", "viewer"), new oso.Value("Repository", "anvil") }, }, }, new List<Fact> { new oso.Fact{ "has_role", new List<Value> { new oso.Value("User", "bob"), new oso.Value("String", "maintainer"), new oso.Value("Repository", "anvil") }, }, })
List facts: oso.Get(name, args)
For Oso Cloud developer accounts, Get
calls are limited to 1000 results. If
you have more than 1000 facts, the function will return an error.
Lists facts that are stored in Oso Cloud. Can be used to check the existence of a particular fact, or used to fetch all facts that have a particular argument:
// Get one fact:oso.Get( "has_role", new List<Value> { new oso.Value("User", "bob"), new oso.Value("String", "admin"), new oso.Value("Repository", "anvil") })// => List<oso.Fact> { oso.Fact{// "has_role",// List<oso.Fact> {// oso.Value("User", "bob"),,// oso.Value("String", "admin"),// oso.Value("Repository", "anvil")// }// }// }// List all roles on the `anvils` repooso.Get( "has_role", new List<Value> { new oso.Value("User", null), new oso.Value("String", null), new oso.Value("Repository", "anvils") })// => List<oso.Fact> { oso.Fact{// "has_role",// List<oso.Fact> {// oso.Value("User", "bob"),,// oso.Value("String", "admin"),// oso.Value("Repository", "anvil")// }// }// }
Note that null
behaves like a wildcard: passing null, null, anvils
means
"find all facts where anvils
is the third argument, regardless of other
arguments".
Check API
For Oso Cloud developer accounts, the number of context facts per request is limited to 20; and the number of records returned is limited to 1000.
Context facts
The Check AP lets you provide context facts with each request. When Oso Cloud performs a check, it considers the request's context facts in addition to any other centralized authorization data. Context facts are only used in the API call in which they're provided-- they do not persist across requests.
For more details, see Context Facts.
Check a permission: oso.Authorize(actor, action, resource)
Determines whether or not an action is allowed, based on a combination of authorization data and policy logic. Example:
var allowed = oso.Authorize(user, "read", anvilsRepository);if (allowed) { // Action is allowed.}
You may provide a slice of context facts. Example:
var allowed = oso.Authorize(user, "read", anvilsRepository, new List<Fact> { new Fact("has_relation", new List<Value> { issueOnAnvilsRepository, new oso.Value("String", "parent"), anvilsRepository })});
Check authorized resources: oso.AuthorizeResources(actor, action, resources)
Returns a subset of resources
on which an actor can perform a particular action.
Ordering and duplicates, if any exist, are preserved.
For Oso Cloud developer accounts, the number of input resources is limited to 1000.
Example:
var results = oso.AuthorizeResources(user, "read", new List<Value> {anvilsRepository, acmeRepository});
You may provide a slice of context facts. Example:
var results = oso.AuthorizeResources(user, "read", new List<Value> {anvilsRepository, acmeRepository}, new List<Fact> { new Fact("has_relation", new List<Value> { issueOnAnvilsRepository, new oso.Value("String", "parent"), anvilsRepository }), new Fact("has_relation", new List<Value> { issueOnAcmeRepository, new oso.Value("String", "parent"), acmeRepository })});
List authorized resources: osoClient.List(actor, action, resourceType)
Fetches a list of resource IDs on which an actor can perform a particular action. Example:
var repositoryIds = oso.List(user, "read", "Repository");
List authorized actions: oso.Actions(actor, resource)
Fetches a list of actions which an actor can perform on a particular resource. Example:
var actions = oso.Actions(user, anvilsRepository);
Query for anything: oso.Query(rule)
Query Oso Cloud for any predicate and any combination of concrete and wildcard arguments.
Unlike oso.Get
, which only lists facts you've added, you can use oso.Query
to list derived
information about any rule in your policy.
Example:
// Query for all the repos `User:bob` can `read`oso.Query( "allow", new List<Value> { new oso.Value("User", "bob"), new oso.Value("String", "read"), new oso.Value("Repository", null) })// => List<oso.Fact> {// oso.Fact{// "allow",// List<oso.Fact> {// oso.Value("User", "bob"),,// oso.Value("String", "read"),// oso.Value("Repository", "acme")// }// },// oso.Fact{// "allow",// List<oso.Fact> {// oso.Value("User", "bob"),,// oso.Value("String", "read"),// oso.Value("Repository", "anvils")// }// },// }// Query for all the objects `User:admin` can `read`oso.Query( "allow", new List<Value> { new oso.Value("User", "admin"), new oso.Value("String", "read"), new oso.Value(null, null) })// => List<oso.Fact> {// // `User:admin` can `read` anything// oso.Fact{// "allow",// List<oso.Fact> {// oso.Value("User", "admin"),,// oso.Value("String", "read"),// oso.Value(null, null)// }// }// }
Note that null
behaves like a wildcard. Passing "allow", null, null, anvils
means "find anyone who can do anything to anvils
". null
also
behaves like a wildcard in return values from oso.Query
. Additionally, if
you want to query over all instances of a particular type, pass an oso.Value
with a Type
but no Id
. For example, "allow", bob, "read", oso.Value("Repository", null)
will query for all the objects of type
"Repository"
that bob
can read
.
[Learn more about how to query Oso Cloud.][query]
List, Actions, and Query can also take Context Facts.
Distributed Check API
The distributed check API lets you perform authorization using data that's distributed across Oso Cloud and your own database.
After creating your local authorization configuration, provide the path to the YAML file that specifies how to resolve facts in your database.
var oso = new Oso(..., dataBindings: "path/to/data_bindings.yaml");
For more information, see Local Authorization.
List authorized resources with distributed data: oso.ListLocal(actor, action, resource_type, column)
Fetches a filter that can be applied to a database query to return just the resources on which an actor can perform an action. Example:
var alice = new Value("User", "alice");var filter = (await oso.ListLocal(alice, "read", "Issue", "id")).Sql;var authorizedIssues = db.Environment.FromSqlRaw($"SELECT * FROM issue WHERE {filter}");
Check a permission with distributed data: oso.AuthorizeLocal(actor, action, resource)
Fetches a query that can be run against your database to determine whether an actor can perform an action on a resource. Example:
var alice = new Value("User", "alice");var swageIssue = new Value("Issue", "swage");var sql = (await oso.AuthorizeLocal(alice, "read", swage_issue)).Sql;var result = AuthorizeResult.FromSqlRaw(sql).Single();if (!result.allowed) { throw new Exception("Action is not allowed")}
List authorized actions with distributed data: oso.ActionsLocal(actor, resource)
Fetches a query that can be run against your database to fetch the actions an actor can perform on a resource.
var alice = new Value("User", "alice");var swageIssue = new Value("Issue", "swage");var sql = (await oso.ActionsLocal(bob, environmentAny)).Sql;var result = db.ActionResult.FromSqlRaw(sql);var actions = result.Select(a => a.Actions).ToList();
Policy API
Update the active policy: oso.Policy(policy)
Updates the policy in Oso Cloud. The string passed into this method should be written in Polar. Example:
oso.Policy("actor User {}")
This command will run any tests defined in your policy. If one or more of these tests fail, your policy will not be updated.
Get policy metadata: oso.get_policy_metadata()
Returns metadata about the currently active policy. Example:
metadata = await oso.GetPolicyMetadata()Console.WriteLine(string.Join(", ", metadata.Resources.Keys));# prints Organization, Repository, User, globalConsole.WriteLine(string.Join(", ", metadata.Resources["Organization"].Roles));# prints admin, member
See the Policy Metadata guide for more information on use cases.
Talk to an Oso Engineer
If you'd like to learn more about using Oso Cloud in your app or have any questions about this guide, schedule a 1x1 with an Oso engineer. We're happy to help.