Hello devs,
In this blog, we will learn how to implement an authorization mechanism in ReactJS applications using Cerbos. Before, let's understand the basics of authorization and why it is needed.
Any application that requires a user login needs an authorization mechanism to control user access to different components of the application. For example, which user can access the admin page, which user can edit, update and delete operations, etc. Authorization is like rules for traffic control and road design. Cars go in the car lanes, bikes use bike lanes, and pedestrians use sidewalks. Pedestrians can enter the car lanes via crosswalks when there is a green walk signal and a corresponding red light for the cars.
The authorization mechanism creates rules in an application to place different types of users in their own lanes. Let's check out the critical elements for authorization below.
To develop this kind of authorization mechanism, key elements need to be designed from scratch or used in conjunction with a third-party tool or library that can provide this mechanism. This can be a time-consuming and complex task. Fortunately, there are alternative solutions!
Here, Cerbos comes into the picture.
Cerbos is an authorization as a service provider. Cerbos empowers you to implement robust authorization in your applications with ease. It centralizes authorization logic, eliminating the need for custom code and simplifying access control management. It replaces your lengthy code with just a few lines by calling Cerbos APIs. Cerbos has multiple features:
There are many tools like this available on the market, so why Cerbos? Why not others? So let's understand this.
Cerbos is designed and developed to be used as a service rather than just a library, which is compiled into an application. This design thinking process provides several benefits.
If you wish to run the Cerbos server locally as a docker container, you can skip the “Setup Cerbos Hub” step below. I’m using the Cerbos hub because it provides me with some extra benefits and ease of access. There are three ways to test Cerbos policy.
Cerbos Playground is a utility for creating and testing policies online. If you aren’t sure how to write a policy, try this policy generator tool: https://play.cerbos.dev/new?generator. You just need to know which page you will control access to and which roles you will have, like admin, user, sales, etc.
Once you create a policy using the generator, just copy it and add it to your playground.
Once you are done with this exercise, you can test the policy by clicking on “Try the API,” which will make you click on the “Save” button. You can also import the same API in Postman and test. Will use the API in React code later in this blog.
Before setting up Cerbos Hub, let's understand what it is exactly.
Cerbos PDP (Policy Decision Point ) is an open-source authorization solution. This is where your application authorization decision is made. A place where all policies, roles, and access are defined, and where authorization is checked while a user accesses the application. PDP can be a cloud instance or a local Docker instance. In other words, it is the endpoint.
Cerbos Hub is a UI console that manages your PDP instances. There are multiple benefits to using Cerbos Hub. But let’s keep that for later. Today, we will use it for its CI/CD implementations that provide Github integration so our policies can automatically get deployed. How does it work?
.cerbos-hub.yaml
in the root folder and copy the following code into the file. You can choose whichever branch you wish to use. In this example, I used the main branch:apiVersion: api.cerbos.cloud/v1
labels:
latest:
branch: main
.cerbos-hub.yaml
is in the root directory or another subdirectory. Then click on “Create a workspace”. docker run --rm --name cerbos \
-p 3592:3592 -p 3593:3593 \
-e CERBOS_HUB_BUNDLE="latest" \
-e CERBOS_HUB_WORKSPACE_SECRET="..." \
-e CERBOS_HUB_CLIENT_ID="..." \
-e CERBOS_HUB_CLIENT_SECRET="..." \
ghcr.io/cerbos/cerbos:0.34.0 server
curl --location 'http://localhost:3592/api/plan/resources' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"action": "read",
"principal": {
"id": "cltjvfunf000014nby8zppt1x",
"roles": [
"admin"
]
},
"resource": {
"kind": "contact"
}
}'
Once you call this API, the response will look like this.
{
"action": "read",
"resourceKind": "contact",
"filter": {
"kind": "KIND_ALWAYS_ALLOWED"
},
"cerbosCallId": "01HS1R87057YXZ0PBC657MN622"
}
If you wish to run a Cerbos server within the demo code locally, create the folder “cerbos” and under that create a file .cerbos.yaml and copy the code below.
storage:
driver: disk
disk:
directory: /basic-crud/policies
watchForChanges: true
You can define the directory file name as you like. I named mine “basic-crud/policies”. You can refer to this file here. Add your resource policies after creating the folder “policies” inside the “cerbos” folder shown in the point #1 screenshot.
Run the command below to use the Cerbos local API. Make sure the mounting drive name “basic-crud” matches the “directory” attribute from the .cerbos.yaml
file.
docker run --rm --name cerbos \
-v $(pwd)/cerbos/:/basic-crud \
-p 3592:3592 \
-p 3593:3593 \
ghcr.io/cerbos/cerbos:latest \
server --config=/basic-crud/.cerbos.yaml
Run a test on http://localhost:3592 for HTTP or http://localhost:3593 for GRPC. Check this API with the below CURL request, or just use the URL in the request to take you to the API documentation page.
Use this CURL command in your terminal or Postman to test the policy:
curl --location 'http://localhost:3592/api/check/resources' \
--data '{
"requestId": "061dfbb1-4d85-4911-925a-b54287ad7879",
"principal": {
"id": "demoUserID",
"roles": [
"marketing"
]
},
"resources": [
{
"actions": [
"read"
],
"resource": {
"kind": "contact",
"id": "1"
}
}
]
}'
We have explored all three possible options for running the Cerbos API. You can use this API URL under the Cerbos configuration, or whichever framework you choose, like React, PHP, or other languages. In this blog, we will cover React. Let's check out how to use Cerbos in React.
In my example code, I will use these roles to explain how access control works.
Install the Cerbos client package in your React code. You can use either GRPC or REST packages. I will choose REST.
npm i @cerbos/http
Create a new file under the lib folder and name it cerbos.ts. Add the below code for Cerbos client integration. There are two ways to call the Cerbos API: one is using the Cerbos Playground instance ID and the second one is directly calling the local API, which we ran under “Setting Up Cerbos Hub” http://localhost:3593.
For a Cerbos Hub PDP instance or Cerbos local API, use this code:
//cerbos.ts
import { HTTP } from "@cerbos/http";
export function getCerbosClient(){
const cerbos = new HTTP("http://localhost:3592");
return cerbos;
}
For Cerbos Playground use the following code in the demo created for both options with the switch.
const cerbos = new HTTP("https://demo-pdp.cerbos.cloud", {
playgroundInstance: "LnQCrZuCzZ660bda75BB9iF2qQdLutza",
});
Import the following file into the required page file. For example, if you have /contact
, then use a relevant .ts file. Refer to the demo code for an example. https://github.com/AvinashDalvi89/react-cerbos-demo
import { getCerbosClient } from "../lib/cerbos";
Then initialize a variable to call the getCerbosClient
function.
const cerbos = getCerbosClient();
Use this code to call cerbos API. Refer to this https://github.com/AvinashDalvi89/react-cerbos-demo/blob/main/src/pages/Admin/Admin.tsx for sample code. The isAllowed
method gives responses as True or False based on access.
await cerbos.isAllowed({
principal: {
id: "user@example.com",
roles: ["USER"],
attr: { tier: "PREMIUM" },
},
resource: {
kind: "document",
id: "1",
attr: { owner: "user@example.com" },
},
action: "view",
})
You can place this code under useEffect()
to add a conditional block to the run page with this check once you get a response back from Cerbos API. You can refer to an example here. https://github.com/AvinashDalvi89/react-cerbos-demo/blob/main/src/pages/Admin/Admin.tsx or see below. The below code uses user “admin” under the “kind” attribute, but you can refer to the actual logic in the demo code. This page code is for the /admin
page. This page will have access to only admin. “User” and “marketing” roles will not have access.
import React, { FC, useState } from 'react';
import { getCerbosClient } from '../../lib/Cerbos';
import { useEffect } from 'react';
const Admin: FC = () => {
const [data, setData] = useState(Boolean);
async function checkAccess() {
const cerbos = getCerbosClient();
const contactQueryPlan = await cerbos.isAllowed({
principal: {
id: "demoUserID",
roles: ["admin"],
attr: { },
},
resource: {
kind: "admin",
id: "1",
},
action: "read",
}); // => true
setData(contactQueryPlan);
return contactQueryPlan;
}
useEffect(() => {
checkAccess();
}, [userDetails]);
if (data) {
return (
<>
<div className='container'>
<h2>Admin Access</h2>
</div>
</>
);
}
else{
return (
<>
<div className='container'>
<h2>Sorry don't have access to this page</h2>
</div>
</>
);
}
}
export default Admin;
Run your React app with a npm start
and try different pages with different roles and add similar code on different pages.
As part of the integration with React, users can choose either Cerbos Hub, local container, or playground options. The choice depends on your use cases.
Want to see how this works? Explore the demo to get a feel for it. Or, if you're interested in diving deeper, you can clone the repository and follow the instructions in the readme.
Book a free Policy Workshop to discuss your requirements and get your first policy written by the Cerbos team
Join thousands of developers | Features and updates | 1x per month | No spam, just goodies.