You can also use Kilpi on the client-side, as long as you have a server-side instance of Kilpi you can connect to using the endpoint plugin. Follow this guide to set up KilpiClient
.
Setup
Install the @kilpi/client
package
npm install @kilpi/client
yarn add @kilpi/client
pnpm add @kilpi/client
bun add @kilpi/client
Setup environment variables
Create public environment variables (e.g. with PUBLIC_
, NEXT_PUBLIC_
or similar prefix to ensure they are included in the client bundle).
PUBLIC_KILPI_URL=http://localhost:3000/api/kilpiPUBLIC_KILPI_SECRET=generate-secret
Setup an authorization endpoint
The Kilpi client requires an endpoint for fetching authorization decisions.
Use the EndpointPlugin from @kilpi/core
to create an authorization endpoint. It exposes the Kilpi.createPostEndpoint()
function, which constructs a web-standard request-response function to use as your endpoint.
import { createKilpi, EndpointPlugin } from "@kilpi/core";
export const Kilpi = createKilpi({ ..., plugins: [ EndpointPlugin({ secret: process.env.PUBLIC_KILPI_SECRET }) ]})
Expose the endpoint using your framework of choice.
export const POST = Kilpi.createPostEndpoint();
const endpoint = Kilpi.createPostEndpoint();
app.post('/api/kilpi', async (c) => await endpoint(c.req.raw));
More guides are coming, but as the Kilpi.createPostEndpoint()
returns a web-standard request-response function, you can use it with any framework that supports web standards, or create a wrapper around it to support web standards yourself.
Create your KilpiClient
instance.
Create your KilpiClient
instance with createKilpiClient
. This object is used to fetch authorization decisions from the server.
Optionally, pass infer
for improved typesafety, and any plugins in plugins
.
import type { Kilpi } from "./kilpi.ts";
export const KilpiClient = createKilpiClient({ infer: {} as typeof Kilpi, // Infer subject and policies from server instance connect: { endpointUrl: process.env.PUBLIC_KILPI_URL, secret: process.env.PUBLIC_KILPI_SECRET, },});
Start using on the client
Now you can use the KilpiClient
instance to fetch the subject and authorization decisions. To enable passing query options, such as abort signals, it has a different signature than the server side Kilpi
instance.
Fetching the subject
// Fetch the subjectconst subject = await KilpiClient.fetchSubject();
// Or optionally with query optionsconst subject = await KilpiClient.fetchSubject({ queryOptions: { signal },});
Fetching authorization decisions
// Fetch authorization decisions for policy without resourceconst canCreateDocument = await KilpiClient.fetchIsAuthorized({ key: "documents:create", queryOptions: { ... } // Optional});
// Fetch authorization decisions for policy with resourceconst canUpdateComment = await KilpiClient.fetchIsAuthorized({ key: "comments:update", resource: comment, queryOptions: { ... } // Optional});
Usage with frontend frameworks
You can use @kilpi/client
with your frontend framework of choice or use one of the provided plugins that provide hooks, components and other bindings for the KilpiClient.
The @kilpi/react-client
package provides hooks and components for using Kilpi with React on the client.
View the documentation for the React Client plugin to start using it.
const KilpiClient = createKilpiClient({ // ..., plugins: [ReactClientComponentPlugin()],});
const { ClientAccess, useSubject, useIsAuthorized} = KilpiClient.ReactClient.createComponents()
function Component() { const subject = useSubject(); const { isAuthorized: canCreateDocuments } = useIsAuthorized("documents:create");
return ( <> {/* Option 1 */} {canCreateDocument && <button>Create document</button>}
{/* Option 2 */} <ClientAccess policy="documents:delete" resource={document} fallback={<p>You are not authorized to create this document</p>} > <p>You are authorized to create this document</p> </ClientAccess> </> )}