> ## Documentation Index
> Fetch the complete documentation index at: https://www.osohq.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 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](/develop/facts/local-authorization). This will instruct Oso to
construct a query to fetch that data directly from your database.

Setup with two requirements:

1. A configuration file that maps your facts to SQL queries
2. Use the [Local Authorization API](/reference/sdks/local-authorization) in your application code

## Write the configuration file

You configure Local Authorization with a yaml file passed to the Oso Cloud
client on instantiation. This configuration file lists the fact signatures
used for your authorization queries. It also 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:

```polar theme={null}
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 to include in the config file.

```yaml local_authorization_config.yaml theme={null}
facts:
  "has_relation(Repository:_, String:parent, Organization:_)":
    query: 'SELECT id, "orgId" FROM "Repository"'
  "has_role(User:_, String:_, Organization:_)":
    query: 'SELECT "userId", role, "orgId" FROM "OrgRole"'
  "has_role(User:_, String:_, Repository:_)":
    query: 'SELECT "userId", role, "repoId" FROM "RepositoryRole"'
sql_types:
  Organization: integer
  Repository: integer
  User: integer
```

Note the following:

* Any value returned by the query is represented in the fact signature by using the wildcard character (`_`).
* Any value 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](/develop/facts/local-authorization#sql-types).

## Use the Local Authorization API

You provide this configuration file to the Oso Cloud client when you
instantiate it. Then you use the [Local Authorization
API](/reference/sdks/local-authorization) to make authorization decisions
without passing data to Oso Cloud.
In the Typescript SDK, you use `authorizeLocal` in place of `authorize`.

```typescript backend/src/authz.ts focus=15-17,21,36-42 theme={null}
import { resolve } from "path";
import { UserWithRoles } from "../authn";
import { Repository, PrismaClient } from "@prisma/client";
import { Oso } from "oso-cloud";
import * as oso from "oso-cloud";

// Make sure the API key is defined and instantiate the client
if (!process.env.OSO_API_KEY) {
  throw "Missing OSO API key from environment";
}

const oso_url = process.env.OSO_URL
  ? process.env.OSO_URL
  : "https://cloud.osohq.com";
const osoClient = new Oso(oso_url, process.env.OSO_API_KEY, {
  dataBindings: resolve("local_authorization_config.yaml"),
});

// A user can read a repo if they have any role on the repo or its parent organization.
export async function canReadRepo(
  prisma: PrismaClient,
  user: UserWithRoles,
  repo: Repository,
): Promise<boolean> {
  const orgRole = user.orgRoles.some((orgRole) => orgRole.orgId == repo.orgId);
  const repoRole = user.repoRoles.some(
    (repoRole) => repoRole.repoId == repo.id,
  );

  const authorizedInline = orgRole || repoRole;

  // entities for Oso
  const osoUser = { type: "User", id: user.id.toString() };
  const osoRepo = { type: "Repository", id: repo.id.toString() };

  // Call authorizeLocal() to return a facts query
  // derived from configuration in local_authorization_config.yaml
  const query = await osoClient.authorizeLocal(osoUser, "read", osoRepo);
  // Run the query
  const rows = await prisma.$queryRawUnsafe<oso.AuthorizeResult[]>(query);
  // Save the result to authorizedOso
  const authorizedOso = rows[0].allowed;

  console.log(
    `User:${user.id} read Repository:${repo.id}: inline: ${authorizedInline}; Oso: ${authorizedOso}`,
  );

  return authorizedInline;
}
```

Major changes are highlighted:

* The `osoClient` instantiation is modified to include the `local_authorization_config.yaml` file.
* The call to `authorize()` is replaced with a call to `authorizeLocal()`
* The query returned from `authorizeLocal()` is executed against the database to resolve the authorization request

Notice that the `canReadRepo()` function is smaller. This is because we do not need code in that function
to get role data and convert it to facts. It is handled by the query returned from `authorizeLocal()` now.

<Info>
  You can write the query that `authorizeLocal()` returns to a log if you'd like
  to inspect it.
</Info>

Confirm that the results from Oso Cloud are still correct.

```console theme={null}
backend  | User:1 read Repository:1: inline: false; Oso: false
backend  | User:1 read Repository:2: inline: true; Oso: true
backend  | User:1 read Repository:3: inline: false; Oso: false
backend  | User:1 read Repository:4: inline: false; Oso: false
backend  | User:1 read Repository:5: inline: false; Oso: false
backend  | User:1 read Repository:6: inline: true; Oso: true
backend  | User:1 read Repository:7: inline: false; Oso: false
backend  | User:1 read Repository:8: inline: false; Oso: false
backend  | User:1 read Repository:9: inline: false; Oso: false
backend  | User:1 read Repository:10: inline: false; Oso: false
```

The results are identical to our previous authorization code.

All that remains is to [replace the original authorization logic with the Oso Cloud version](/learn/guides/adopt-local-authorization/authorize-with-oso-cloud).
