Shareable Content
If you're building an application that supports user-generated content (docs, notes, images etc), chances are that you'll also need to build functionality that allows users to share and collaborate on that content. Building such a system can get very complicated very fast.
In this guide, we'll go over how you can use Warrant to quickly augment your existing application to add sharing and collaboration functionality.
Prerequisites
This guide exclusively uses the Warrant API and thus assumes you have a Warrant account with API keys. If you don't, please first follow the Getting Started guide to set up your account.
Creating Object Types for Each Content Type
Each explicit 'content type' (ex. document, note, image) in our application will require an object type definition in Warrant. Let's say for example that we're building a simplified version of Google Docs. This simplified version has exactly 1 type of content: document
. Each 'document' has an 'owner', 'editor(s)' and 'viewer(s)'. Using these relations, we can easily define who can read and/or modify a specific document in our application.
For each distinct 'content type' in your application, you should create an object type with 'owner', 'editor' and 'viewer' relationships. Note that these permissions cascade, with owners having editor and viewer privileges and editors also having viewer privileges:
- JSON
- cURL
{
"type": "document",
"relations": {
"owner": {},
"editor": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "owner"
}
]
}
"viewer": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "editor"
}
]
}
}
}
curl "https://api.warrant.dev/v1/object-types" \
-X POST \
-H "Authorization: ApiKey YOUR_KEY" \
--data-raw \
'{
"type": "document",
"relations": {
"owner": {},
"editor": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "owner"
}
]
}
"viewer": {
"type": "anyOf",
"rules": [
{
"type": "userset",
"relation": "editor"
}
]
}
}
}'
Granting Permissions
With our object types defined, we can create warrants that grant 'editor' and 'viewer' access to specific objects. For example, let's say that we have a 'document' in our application with id 'doc1'. We can grant a user (user1) 'editor' access to this document by creating the following warrant:
- cURL
- Node.js
- Go
- Python
- Java
curl "https://api.warrant.dev/v1/warrants" \
-X POST \
-H "Authorization: ApiKey YOUR_KEY" \
--data-raw \
'{
"objectType": "document",
"objectId": "doc1",
"relation": "editor",
"user": {
"userId": "user1"
}
}'
client
.createWarrant("document", "doc1", "editor", { userId: "user1" })
.then((newWarrant) => console.log(newWarrant))
.catch((error) => console.log(error));
resp, err := client.CreateWarrant(warrant.Warrant{
ObjectType: "document",
ObjectId: "doc1",
Relation: "editor",
User: warrant.WarrantUser{
UserId: "user1",
},
})
if err != nil {
fmt.Println(err.Error())
} else {
fmt.Println(resp)
}
client.create_warrant(object_type="document", object_id="doc1", relation="editor", user="user1")
try {
client.createWarrant(Warrant.newUserWarrant("document", "doc1", "editor", "user1"));
} catch (WarrantException e) {
// Handle error
}
Checking Permissions
With our content permissions defined via warrants, we can start to enforce access to content directly in the app.
For example, if we wanted to check whether 'user1' had the ability to 'edit' 'doc1', we would add the following check in our application code:
- cURL
- Node.js
- Go
- Python
- Java
curl "https://api.warrant.dev/v1/warrants" \
-X POST \
-H "Authorization: ApiKey YOUR_KEY" \
--data-raw \
'{
"objectType": "document",
"objectId": "doc1",
"relation": "editor",
"user": {
"userId": "user1"
}
}'
client
.isAuthorized("document", "doc1", "editor", "user1")
.then((isAuthorized) => {
if (isAuthorized) {
// 'user1' can edit doc1
}
})
.catch((error) => console.log(error));
isAuthorized, _ := client.IsAuthorized(warrant.Warrant{
ObjectType: "document",
ObjectId: "doc1",
Relation: "editor",
User: warrant.WarrantUser{
UserId: "user1",
},
})
if isAuthorized {
// 'user1' can edit doc1
} else {
// Fail request
}
is_authorized = client.is_authorized(object_type="document", object_id="doc1", relation="editor", user_to_check="user1")
if is_authorized:
# 'user1' can edit doc1
else:
# Fail request
boolean isAuthorized = client.isAuthorized(Warrant.newUserWarrant("document", "doc1", "editor", "user1"));
if (isAuthorized) {
// 'user1' can edit doc1
} else {
// Fail request
}
Summary
In this guide, we went over how you can use Warrant to quickly implement an access model for 'shareable content'. By assigning each object type an 'owner', 'editor(s)' and 'viewer(s)', we can easily implement logic in our application to manage and enforce content permissions at runtime.