Bulk Check
The permit bulk check()
function allows you to validate multiple permission requests in a single call.
For some use cases, you might need to perform multiple check()
calls at once.
To support that, Permit provides a bulkCheck
function that allows you to validate multiple permission requests in a single call.
In its basic form, the bulk check()
function accepts the same parameters as the check()
function, but in an array.
- Node.js
- Java
- GoLang
const { Permit } = require("permitio");
const permit = new Permit({token: "<YOUR_API_KEY>", ...});
await permit.bulkCheck([
{ user: "john@doe.com", action: 'read', resource: "document" },
{ user: "jane@doe.com", action: 'create', resource: "document" },
]);
import io.permit.sdk.Permit;
import io.permit.sdk.PermitConfig;
import io.permit.sdk.enforcement.*;
import java.util.Arrays;
Permit permit = new Permit(
new PermitConfig.Builder("[YOUR_API_KEY]").build()
);
boolean[] checks = permit.bulkCheck(Arrays.asList(
// positive permission check
new CheckQuery(
User.fromString("john@doe.com"),
"read",
new Resource.Builder("document").withTenant(tenant.key).build()
),
// negative permission check
new CheckQuery(
User.fromString("john@doe.com"),
"create",
new Resource.Builder("document").withTenant(tenant.key).build()
)
));
package main
import (
"fmt"
)
import p "github.com/permitio/permit-golang/pkg/permit"
import "github.com/permitio/permit-golang/pkg/config"
import "github.com/permitio/permit-golang/pkg/enforcement"
func main() {
// Create permit client
permitConfig := config.NewConfigBuilder("").Build()
permit := p.New(permitConfig)
requestContext := map[string]string{
"source": "docs",
}
usersToCheck := []string{
"john@doe.com",
"jane@doe.com",
}
checkRequests := make([]enforcement.CheckRequest, len(usersToCheck))
// Create the requests to check
resource := enforcement.ResourceBuilder("document").Build()
for i, userKey := range usersToCheck {
user := enforcement.UserBuilder(userKey).Build()
checkRequests[i] = *enforcement.NewCheckRequest(user, "read", resource, requestContext)
}
var results []bool
// Perform the bulk check
results, err := permit.BulkCheck(checkRequests...)
if err != nil {
fmt.Printf("Error enforcing permissions: %s", err)
} else {
// The response indexes correspond to the request indexes
for i, request := range checkRequests {
if results[i] {
fmt.Printf("%d. User '%s' is PERMITTED to '%s' a '%s'\n",
i, request.User.Key, request.Action, request.Resource.Type,
)
} else {
fmt.Printf("%d. User '%s' is NOT PERMITTED to '%s' a '%s'\n",
i, request.User.Key, request.Action, request.Resource.Type,
)
}
}
}
}
Use Cases
Below are some examples of the use cases that require the use of the bulkCheck()
function:
Latency Sensitive Applications
The most basic usage of a bulkCheck
is to save time when multiple check calls are needed in one scope.
For example, assuming we have an API endpoint that performs multiple actions on a resource, we can use the bulkCheck
function to check all the permissions at once.
const permitted = await permit.bulkCheck([
{ user, "create", "document" },
{ user, "edit", "profile"}
]);
Multiple Policy Models
In some cases, we want to perform ReBAC and ABAC checks for the same operations.
For example, if edit
is a premium feature in our application (with ABAC) and we also want to check if the user has access to edit
a document (with ReBAC), we can use the bulkCheck
function to check both permissions at once.
const {key, tier} = getUser(token);
const permissions = await permit.bulk([
// Checking for relationship to the particular document
{ user: key, "edit", `document:${document.id}` },
// Checking for the user's tier by user attributes
{ user: {key , attributes: {tier}}, "edit", `document:${document.id}` }
]);
const permitted = permissions[0] || permissions[1];
Data Filtering
Data filtering is where we have a collection of data, and we want to filter it based on the permissions of the user.
While there are more efficient ways to perform data filtering with Permit, mapping mutliple permissions checks to a single bulkCheck
call can be useful in some cases.
const resources = getResources();
const permitted = await permit.bulkCheck(
resources.map(resource => ({ user, "read", resource })
));
const permittedResources = resources.filter(
(resource, index) => permitted[index]
);
Set Timeout
Bulk checking is more performance-intensive than regular checking and also takes more time, which can lead to an OPA timeout. To address this issue, you can increase the query timeout for the PDP and add more CPU to your virtual machine.
If for example you want a 10 second timeout, you can set the environment variable as follows:
PDP_OPA_CLIENT_QUERY_TIMEOUT=10
For more information on system requirements and performance optimization, you can check this documentation.
While bulkCheck
will save you time in latency, it could have an impact on performance if you're checking permissions for different tenants.
This is because requests are split by tenant in order to reach the relevant PDP instances. This is done in order to ensure compatibility with the current PDP Sharding setup, in which an instance might only contain data for a few tenants.