> ## 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.

# Extract authorization logic

# Extract a Piece of Authorization Logic

## Identify the logic to extract

First, select a piece of authorization logic to move to Oso Cloud. For your section of logic should be:

* Well understood
* Low-impact
* Straightforward to extract

In this guide, the process of migration to local authorization is illustrated with code samples from a hypothetical version control application. You can follow along with those or you use examples from your code.

One permission this version control application requires is the ability to `read` a repository. That permission affects two operations:

1. `read` a single repository
2. list all the repositories that the user can `read`

The logic resides in the corresponding `get` handlers:

```typescript focus=1:3,17:12,21:22 theme={null}
// Return the requested repository if the user has permission to read it
accountsRouter.get(
  "/orgs/:orgId/repos/:repoId",
  withAuthn,
  async (req, res) => {
    const user = await currentUser(req);
    const orgRole = user.orgRoles.find(
      (orgRole) => orgRole.orgId == parseInt(req.params.orgId)
    );
    const repoRole = user.repoRoles.find(
      (repoRole) => repoRole.repoId == parseInt(req.params.repoId)
    );

    const repo: WithPermissions<Repository> | null =
      await req.prisma.repository.findUnique({
        where: {
          orgId: parseInt(req.params.orgId),
          id: parseInt(req.params.repoId),
        },
      });
    if (repo && (orgRole || repoRole)) {
      repo.permissions = ["read"];

        ...

    }
  }
);
```

```typescript focus=1:2,7:15 theme={null}
// List all repos that the user can read in the specified org
accountsRouter.get("/orgs/:orgId/repos", withAuthn, async (req, res) => {
  let repos = await req.prisma.repository.findMany({
    where: { orgId: parseInt(req.params.orgId) },
  });
  const user = await currentUser(req);
  const memberOfOrg = user.orgRoles.some(
    (orgRole) => orgRole.orgId == parseInt(req.params.orgId),
  );
  repos = repos.filter((repo) => {
    return (
      memberOfOrg ||
      user.repoRoles.some((repoRole) => repoRole.repoId == repo.id)
    );
  });
  res.send(repos);
});
```

This is typical of authorization code:

* The same logic is implemented in multiple places
* The implementation slightly differs in each place
* It is not obvious it is critical authorization logic

This is a good candidate for early refactoring:

* The logic is straightforward - a user can read a repository if:
  * They have any role on the repository
  * They have any role on the repository's parent organization
* It only grants read access.
* The logic is already encapsulated.

## Extract the logic into a dedicated function

With a piece of logic to refactor identified, extract it into a dedicated function. This decouples the authorization logic from the surrounding application logic.

Create a function called `canReadRepo()` in a new file called `authz.ts`. That makes it obvious which permission it governs.

```typescript src/authz.ts theme={null}
// A user can read a repo if they have any role on the repo or its parent organization.
function canReadRepo(user: UserWithRoles, repo: Repository): boolean {
  const orgRole = user.orgRoles.some((orgRole) => orgRole.orgId == repo.orgId);
  const repoRole = user.repoRoles.some(
    (repoRole) => repoRole.repoId == repo.id,
  );

  return orgRole || repoRole;
}
```

Now you call this function when you authorize a user's request to read a repository.

```typescript src/routes/accounts.ts focus=1,10 theme={null}
import { canReadRepo } from "../authz";

// List all repos that the user can read in the specified org
accountsRouter.get("/orgs/:orgId/repos", withAuthn, async (req, res) => {
  let repos = await req.prisma.repository.findMany({
    where: { orgId: parseInt(req.params.orgId) },
  });
  const user = await currentUser(req);
  repos = repos.filter((repo) => {
    return canReadRepo(user, repo);
  });
  res.send(repos);
});
```

```typescript src/routes/accounts.ts focus=15:25 theme={null}
// Return the requested repository if the user has permission to read it
accountsRouter.get(
  "/orgs/:orgId/repos/:repoId",
  withAuthn,
  async (req, res) => {
    const user = await currentUser(req);
    const repo: WithPermissions<Repository> | null =
      await req.prisma.repository.findUnique({
        where: {
          orgId: parseInt(req.params.orgId),
          id: parseInt(req.params.repoId),
        },
      });

    if (repo && canReadRepo(user, repo)) {
      repo.permissions = ["read"];

      ...

    }
  }
);
```

Even this change provides meaningful benefits:

* A dedicated file for authorization logic (`src/authz.ts`).
* The logic for the "read repository" permission is easy to find, understand, and reason about.
* The logic is defined only once.
* The application code is cleaner.

Next, [implement the logic in Oso Cloud](/learn/guides/adopt-local-authorization/implement-in-oso-cloud).
