The authorization rules that secure your application’s backend often have
implications for the frontend user interface (UI) as well. For example, if a user
does not have access to a specific page the UI should hide that link.
Similarly, if a user can only read a resource, the UI may gray out an edit
button.
This guide covers the best practices for implementing frontend (UI)
authorization with Oso Cloud.
Keep Enforcement in the Backend
The first rule of frontend authorization: keep the user interface in charge of
presentation and the backend service in charge of enforcement. Because the end user has
total control over code that runs in their browser, you can never
trust requests from the UI. The user might represent as an administrator who
should have unfettered access to your entire application. But thebackend
service should request an authorization decision from Oso Cloud to confirm
what they are permitted to do.
For security reasons, you should never make requests directly to Oso Cloud
from your frontend. Your Oso Cloud API token should be kept secret and never
exposed in a user interface. A malicious actor could use even a read-only
API token to exfiltrate your sensitive authorization policy and data.
Expose Permissions to the Frontend
UIs ask a single authorization question over and over: what actions can
the current user perform on resources rendered on the current page? If
the user can view an organization but does not have permission to
edit or delete it, the user interface should not render Edit or Delete buttons.
The general pattern for a backend service responding to an user interface request:
- Ask Oso Cloud via the Authorize API: is the user authorized to
access the resource?
- If they have access, what actions can the user take on the resource?
- Return the permissions along with the response payload so that your UI
can render the approriate experience based on what the user can and cannot
do.
Here’s an example of that pattern in our GitCloud example
app’s Python back end:
def show_organization(org_id):
# Is the current user authorized to access the resource?
if not oso.authorize(current_user, "read", {"type": "Organization", "id": org_id}):
raise NotFound
org = Organization.get_from_database(org_id)
json = org.as_json()
# What actions can the current user take on the resource?
actions = oso.actions(current_user, org)
# Return the permissions along with the response payload.
json["permissions"] = actions
return json
The UI then uses the returned permissions to decide whether to show or
hide specific elements. Here’s an example from GitCloud’s
React front end:
{
org.permissions?.includes("create_repositories") && (
<Button>Create new repository</Button>
);
}
We only show the Create new repository button if the current user has the
"create_repositories" permission on the organization.
More Resources