Skip to main content

Fine Grained Access Control (FGAC)

Implementing an authorization scheme in Warrant involves 3 steps: (1) defining your data model (creating object types), (2) creating access rules (warrants), and (3) implementing access checks in your code. In this quickstart, we'll go through these 3 steps for implementing fine grained authorization in a simple eCommerce application.

1. Creating Object Types

Although Warrant ships with built-in object types for user, role, permission, and tenant, you may have a use case that requires your own custom object types.

For our eCommerce application, we'll create a store object type:

{
"type": "store",
"relations": {
"owner": {},
"creator": {},
"editor": {
"inheritIf": "owner"
},
"viewer": {
"inheritIf": "editor"
}
}
}

A store has the following direct and inherited relations:

  • A store can have an owner (direct)
  • A store can have a creator (direct)
  • A store can have an editor (direct)
  • An owner of a store is also an editor of that store (inherited)
  • A store can have a viewer (direct)
  • An editor of a store is also a viewer of that store (inherited)

Object types can be created directly in the dashboard or via the Object Types API:

curl "https://api.warrant.dev/v1/object-types" \
-X POST \
-H "Authorization: ApiKey YOUR_KEY" \
--data-raw \
'{
"type": "store",
"relations": {
"owner": {},
"creator": {},
"editor": {
"inheritIf": "owner"
},
"viewer": {
"inheritIf": "editor"
}
}
}'

2. Creating Warrants

Once our object types are defined, we can create warrants that define our application's specific access control rules. Warrants are typically created from within your application business logic through the Warrants API (via REST or one of the SDKs).

We can use the built-in user object type and our store object type to create a warrant specifying that [user:d6ed6474-784e-407e-a1ea-42a91d4c52b9] is an [editor] of [store:7]:

curl "https://api.warrant.dev/v1/warrants" \
-X POST \
-H "Authorization: ApiKey YOUR_KEY" \
--data-raw \
'{
"objectType": "store",
"objectId": "7",
"relation": "editor",
"subject": {
"objectType": "user",
"objectId": "d6ed6474-784e-407e-a1ea-42a91d4c52b9"
}
}'

3. Authorizing Users

Now that we have object types, users, and warrants set up, we can start authorizing user access to our system. At minimum, we should have server-side checks but we can also implement client-side authorization using Warrant sessions and UI components.

Server-side Authorization

At a high-level, server-side authorization involves making a POST /v2/authorize request to Warrant with the given warrants that you want to verify authorization for through each endpoint. For example, if your server implements a PUT /stores endpoint, you may want to only allow users with the editor relation on stores to perform that action. You can authorize a user by making a request to Warrant:

curl "https://api.warrant.dev/v2/authorize" \
-X GET \
-H "Authorization: ApiKey YOUR_KEY" \
--data-raw \
'{
"warrants": [
{
"objectType": "store",
"objectId": "7",
"relation": "editor",
"subject": {
"objectType": "user",
"objectId": "d6ed6474-784e-407e-a1ea-42a91d4c52b9"
}
}
]
}'

This call will return a 200 OK if successful. The response body will contain "result": "Not Authorized" if user 6ed6474-784e-407e-a1ea-42a91d4c52b9 does not have the editor relation on store 7 and "result": "Authorized" if the user does have the relation.

Client-side Authorization

If your client application is a Single Page App (SPA) or a native mobile application (iOS/Android), implementing client-side authorization using Warrant will further secure your application and help you more cleanly display different UI/UX for users with different levels of access. We currently provide SDKs for client-side authorization in applications built using React, NextJS, and VueJS. Refer to our guides on using Warrant with React, NextJS, and VueJS for a step-by-step tutorial.