Piplup
@piplup/react-aclHooks

useAcl

Read the ACL loading state and run role and permission checks in code with isAuthorized.

useAcl returns the isAuthorized function and loading flag from the nearest AclProvider. HasAccess is built on it.

Use HasAccess when you show or hide a piece of markup. Use useAcl when you need the answer as a value: filtering a list of actions, disabling instead of hiding, choosing a redirect, or checking access inside an event handler.

Import

import { useAcl } from "@piplup/react-acl";

Usage

The toolbar keeps only the actions the current user may run, and the Export button checks the user's role when it is clicked.

Current user
"use client";import * as React from "react";import Button from "@mui/material/Button";import MenuItem from "@mui/material/MenuItem";import Stack from "@mui/material/Stack";import TextField from "@mui/material/TextField";import Typography from "@mui/material/Typography";import { AclProvider, useAcl } from "@piplup/react-acl";const roleOptions = {  guest: { roles: ["guest"], permissions: [] },  editor: { roles: ["editor"], permissions: ["post:create", "post:publish"] },  owner: { roles: ["owner"], permissions: ["post:create", "post:publish", "post:delete"] },};type Role = keyof typeof roleOptions;const actions = [  { label: "New post", permissions: "post:create" },  { label: "Publish", permissions: "post:publish" },  { label: "Delete", permissions: "post:delete" },];function PostToolbar() {  const { isAuthorized, loading } = useAcl();  // A single value works as well as an array.  const visible = actions.filter((action) => isAuthorized({ permissions: action.permissions }));  // Check a role in an event handler, not only while rendering.  const handleExport = () => {    alert(isAuthorized({ roles: ["editor", "owner"] }) ? "Exporting posts" : "Sign in to export");  };  if (loading) {    return <Typography>Checking access...</Typography>;  }  return (    <Stack direction="row" spacing={1} sx={{ flexWrap: "wrap" }}>      {visible.map((action) => (        <Button key={action.label} variant="contained">          {action.label}        </Button>      ))}      <Button variant="outlined" onClick={handleExport}>        Export      </Button>    </Stack>  );}export default function Page() {  const [role, setRole] = React.useState<Role>("editor");  const { roles, permissions } = roleOptions[role];  return (    <Stack spacing={2}>      <TextField        select        size="small"        label="Current user"        value={role}        onChange={(e) => setRole(e.target.value as Role)}        sx={{ maxWidth: 200 }}      >        {Object.keys(roleOptions).map((name) => (          <MenuItem key={name} value={name}>            {name}          </MenuItem>        ))}      </TextField>      <AclProvider loading={false} roles={roles} permissions={permissions}>        <PostToolbar />      </AclProvider>    </Stack>  );}

isAuthorized

type IsAuthorized = (check: {
  roles?: (number | string)[] | number | string;
  permissions?: (number | string)[] | number | string;
  validationMode?: { roles?: "all" | "any"; permissions?: "all" | "any" };
}) => boolean;

It follows the same rules as HasAccess: roles and permissions must both pass, an omitted or empty list passes, and each list defaults to any. See how access is decided.

Unlike the HasAccess props, roles and permissions also accept a single value, so isAuthorized({ permissions: "post:delete" }) works without wrapping it in an array.

Loading

isAuthorized returns false for every call while the provider's loading is true, even for a check with no requirements. Check loading first, so you can tell "still loading" apart from "denied":

function DeleteButton() {
  const { isAuthorized, loading } = useAcl();

  return (
    <button disabled={loading || !isAuthorized({ permissions: "post:delete" })}>
      Delete
    </button>
  );
}

isAuthorized changes identity when the provider's roles, permissions or loading change. If you use it inside useEffect, useMemo or useCallback, list it as a dependency so the result is recomputed after a role change.

useAcl throws AclProvider must be rendered as parent before using useAcl when it is called outside an AclProvider. This also applies to HasAccess.

Return value

Prop

Type

On this page