Skip to main content

Using Warrant with React

The Warrant React SDK allows you to securely add authorization & access control checks directly in your React application to show/hide pages, components, and other content that requires privileged access. The SDK interacts directly with the Warrant API using short-lived session tokens that must be created server-side using your API key. Refer to our guide on Creating Sessions to learn how to generate session tokens you can pass to the Warrant React SDK to start performing client-side access checks.

The following guide assumes that you already have a Warrant account and corresponding API and Client keys. If you don't already have an account, you can sign up for one here.

note

The Warrant React SDK is intended for use in client-side applications to perform access checks that dictate the rendering of pages and components. Always ensure that server-side actions which modify state in your application (ex: an API call that writes to the database) are protected using one of Warrant's server-side SDKs. To learn how to add server-side access checks using Warrant, refer to this quickstart guide.

Create an Allowed Origin

Since the Warrant React SDK interacts directly with the Warrant API, you must first configure an Allowed Origin from the Warrant Dashboard to allow requests from your React application to the Warrant API. Requests from an origin not explicitly specified by an Allowed Origin will fail.

For example, if your React application is served at https://app.example.com, create an Allowed Origin for https://app.example.com to allow requests from that origin.

For local development, you can add an Allowed Origin for localhost. For example, if your local React application is being served on localhost port 3000, add an Allowed Origin for http://localhost:3000.

Allowed Origins support wildcards (*), so creating an Allowed Origin for https://*.example.com will allow requests coming from any subdomain of https://example.com such as https://foo.example.com and https://bar.example.com.

Install the SDK

Run the following command in your project directory to install the Warrant React SDK:

npm install @warrantdev/react-warrant-js

Add WarrantProvider

The Warrant React SDK uses React Context to allow you to access utility methods for performing access checks anywhere in your app. Wrap your application with WarrantProvider, passing it your Client Key using the clientKey prop.

App.jsx
import React from "react";
import { WarrantProvider } from "@warrantdev/react-warrant-js";

const App = () => {
return (
<WarrantProvider clientKey="client_test_f5dsKVeYnVSLHGje44zAygqgqXiLJBICbFzCiAg1E=">
{/* Routes, ThemeProviders, etc. */}
</WarrantProvider>
);
};

export default App;

Set the Session Token

To finish initializing the SDK you must call the setSessionToken method with a valid session token. This allows the SDK to make access check requests to the Warrant API. Refer to our guide on Creating Sessions to learn how to generate session tokens. We recommend generating a session token for the user during your authentication flow. You can then return the token to the client and use it to initialize the SDK. Here's an example of what that might look like:

Login.jsx
import React from "react";
import { useWarrant } from "@warrantdev/react-warrant-js";

const Login = () => {
const { setSessionToken } = useWarrant();

const loginUser = async (event) => {
const response = await login(email, password);

// NOTE: This session token must be generated
// server-side when logging users into your
// application and then passed to the client.
// Access check calls in this library will fail
// if the session token is invalid or not set.
setSessionToken(response.warrantSessionToken);

//
// Redirect user to logged in page
//
};

return (
<form onSubmit={loginUser}>{/* email & password inputs, etc. */}</form>
);
};

export default Login;

Protect Routes

withWarrant

withWarrant is a Higher Order Component (HOC) that can be wrapped around routes and components that should only be accessible to users who have access. Given warrants, the HOC will automatically perform an access check and only render the wrapped component if the user has access. If warrants contains multiple warrants, the op parameter is required and specifies how the list of warrants should be evaluated.

anyOf specifies that the access check request will be authorized if any of the warrants are matched and will not be authorized otherwise.

allOf specifies that the access check request will be authorized if all of the warrants are matched and will not be authorized otherwise.

Use withWarrant to add protected routes to your application like so:

import React from "react";
import { Router, Route, Switch } from "react-router-dom";
import { createBrowserHistory } from "history";
import { WarrantProvider, withWarrant } from "@warrantdev/react-warrant-js";

const history = createBrowserHistory();

const App = () => {
return <WarrantProvider clientKey="client_test_f5dsKVeYnVSLHGje44zAygqgqXiLJBICbFzCiAg1E=">
<Router history={history}>
<Switch>
<Route path="/public_route" exact component={PublicPage}/>
{/*
Only render ProtectedPage if the user
is a "viewer" of the route "protected_route".
*/}
<Route path="/protected_route" exact component={withWarrant(ProtectedPage, {
warrants: [{
objectType: "route",
objectId: "protected_route",
relation: "viewer",
}],
redirectTo: "/public_route",
})}>
</Switch>
</Router>
</WarrantProvider>;
};

export default App;

NOTE: The above example uses react-router but you can use any routing library with the Warrant React SDK.

ProtectedRoute

If you're using react-router to manage routing in your app, you can make use of the ProtectedRoute component instead of withWarrant to protect your routes.

import React from "react";
import { Router, Route, Switch } from "react-router-dom";
import { createBrowserHistory } from "history";
import { WarrantProvider, ProtectedRoute } from "@warrantdev/react-warrant-js";
import PublicPage from "./PublicPage";
import ProtectedPage from "./ProtectedPage";

const history = createBrowserHistory();

const App = () => {
return (
<WarrantProvider clientKey="client_test_f5dsKVeYnVSLHGje44zAygqgqXiLJBICbFzCiAg1E=">
<Router history={history}>
<Switch>
<Route path="/public_route" exact component={PublicPage} />
<ProtectedRoute
path="/protected_route/:id"
key="/protected_route/:id"
exact
component={ProtectedPage}
options={{
warrants: [{
objectType: "myObject",
objectId: "id",
relation: "viewer",
}],
redirectTo: "/public_route",
}}
/>
</Switch>
</Router>
</WarrantProvider>
);
};

export default App;

Add Access Checks in Components

Sometimes a page or component should be visible to all users, but not all of its functionality should be. ProtectedComponent and hasWarrant are a component and a utility method that allow you to add more granular access checks within components.

hasWarrant

Make specific access checks within a component using hasWarrant:

import React, { useEffect } from "react";
import { useWarrant } from "@warrantdev/react-warrant-js";

const MyComponent = () => {
const { hasWarrant } = useWarrant();

useEffect(() => {
const fetchProtectedInfo = async () => {
// Only fetch protected info from server if
// user is a "viewer" of the info object "protected_info".
const userHasWarrant = await hasWarrant({
warrants: [{
objectType: "info",
objectId: "protected_info",
relation: "viewer",
}]
});
if (userHasWarrant) {
// request protected info from server
}
};

fetchProtectedInfo();
});

return (
<div>{protectedInfo && <ProtectedInfo>{protectedInfo}</ProtectedInfo>}</div>
);
};

export default MyComponent;

ProtectedComponent

Wrap components in ProtectedComponent to only render them if the user has the required access:

import React from "react";
import { ProtectedComponent } from "@warrantdev/react-warrant-js";

const MyComponent = () => {
return (
<div>
<MyPublicComponent />
{/* hides MyProtectedComponent unless the user is a "viewer" of myObject with id object.id */}
<ProtectedComponent
warrants={[{
objectType: "myObject",
objectId: object.id,
relation: "viewer",
}]}
>
<MyProtectedComponent />
</ProtectedComponent>
</div>
);
};

export default MyComponent;