# Implement permissions via relationships?

**URL:** <https://discuss.jsonapi.org/t/implement-permissions-via-relationships/612>\
**Category:** Uncategorized\
**Created:** [August 3, 2016, 7:15pm UTC](https://discuss.jsonapi.org/t/implement-permissions-via-relationships/612 "2016-08-03T19:15:30Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![morris](https://avatars.discourse-cdn.com/v4/letter/m/d2c977/32.png) [@morris](https://discuss.jsonapi.org/u/morris)\
**Post date:** [August 3, 2016, 7:15pm UTC](https://discuss.jsonapi.org/t/implement-permissions-via-relationships/612/1 "2016-08-03T19:15:30Z")

</div>

Hi I am working on a unix-style permissions system where every row in the database has a unique id so that a resource\_user\_permissions table like `[resource_id][user_id][permissions]` can be implemented to provide user-level access to resources. Each resource is analogous to an inode from unix.

I’m running into a situation where a resource may contain other resources that are public. I can’t reveal the other resource’s id, because any user can go to a `/resources/{resource_id}` endpoint to look that resource up by id. I think I am hitting a problem similar to wanting read permissions but not execute (list contents) permissions on a unix directory. I need something even more granular to limit listing a container’s specific relationships.

So for example imagine a user’s directory (`1 my_user`) that contains references to other resources on the site owned by other users. If I want to make it so that a different user (`5 some_user`) can’t see a resource in the first directory, I can’t assign a `no_access` permission to resource `5` because I’m not that resource’s owner. I need to somehow assign `no_access` to the directory-resource relationship. It appears I have two options:

* * *

OPTION 1) list resources as relationships so that multiple ids correspond to one resource and permissions can be applied to the relationship id:

Structure:

```
2 my_directory
    37 my_resource (a relationship resource that points to 3 my_resource)
    42 someone_elses_resource (a relationship resource that points to 4 someone_elses_resource)

```

JSON:

```
{
	"data": {
		"type": "directories",
		"id": 2,
		"relationships": {
			"resources": {
				"data": [
					{
						"type": "resources",
						"id": 37
					},
					{
						"type": "resources",
						"id": 42
					}
				]
			}
		}
	}
}

```

So a request to add `5 some_user` to a blocks collection to prevent it from reading `4 someone_elses_resource` might look like:

```
POST /directories/2/resources/42/blocks
{
	"data": {
		"type": "users",
		"id": 5
	}
}

```

This would add a row like `[42][5][no_access]` to the permissions table.

The downside is that all ids are now auto-generated and unique per path so none of the usual POST/PUT/DELETE calls to endpoints would work (because the client only knows resource ids, not path-dependent relationship ids). Requests would require two trips to fetch a relationship id for a resource and then submit that relationship id.

* * *

OPTION 2) list resources directly and set permissions on relationships:

Structure:

```
2 my_directory
    3 my_resource
    4 someone_elses_resource

```

JSON:

```
{
	"data": {
		"type": "directories",
		"id": 2,
		"relationships": {
			"resources": {
				"data": [
					{
						"type": "resources",
						"id": 3
					},
					{
						"type": "resources",
						"id": 4
					}
				]
			}
		}
	}
}

```

So a request to add `5 some_user` to a blocks collection to prevent it from reading `4 someone_elses_resource` might look like:

```
POST /directories/2/relationships/resources/4/blocks
{
	data:
	{
		type: "users",
		id: "5"
	}
}

```

This would add a row like `[42][5][no_access]` to the permissions table by looking up relationship id `42` for `4 someone_elses_resource` behind the scenes.

* * *

I’m leaning towards option 2 but I’m having a hard time understanding how relationships work from the documentation. I understand how a one-to-one relationship is specified, but are we allowed to append additional path elements beyond the `/relationships/{relationship}/` portion of the URL? For example blocking `5 some_user` from reading `1 my_user`'s profile might look like:

```
POST /users/1/relationships/profile/blocks
{
	data:
	{
		type: "users",
		id: "5"
	}
}

```

But I am not clear if it’s ok to use an endpoint like `/directories/2/relationships/resources/4/blocks` where I specify the related resource’s id in the URL.

I think the gist of the problem is that I would like to set permissions on a relationship like it’s a first-class resource, but I don’t want to reveal the relationship id to the client (due to the added complexity of doing so).

I have found some examples on the web where REST APIs have attribute-level permissions. I’m concerned though that this could be a can of worms and nonstandard. If it’s possible to treat everything as an inode and stick with unix-style permissions, I’d prefer to do that.

I realize this touches on both permissions and relationships which can be nebulous, and that my examples and terminology might not be that great. I feel like I’m not seeing something fundamental here. Any insights you can provide about permissions with respect to REST API design would be greatly appreciated, thanks!

---

<div class="post-metadata">

**Author:** ![jlangley](https://avatars.discourse-cdn.com/v4/letter/j/9e8a1a/32.png) [@jlangley](https://discuss.jsonapi.org/u/jlangley)\
**Post date:** [August 3, 2016, 9:37pm UTC](https://discuss.jsonapi.org/t/implement-permissions-via-relationships/612/2 "2016-08-03T21:37:48Z")

</div>

> [@morris](#):
>
> are we allowed to append additional path elements beyond the /relationships/{relationship}/ portion of the URL?

There are [no restrictions](http://jsonapi.org/recommendations/#urls) on URL design; however, `/directories/2/relationships/resources/4/blocks` is **not** an idiomatic JSON API URL.

Idiomatically, if you want to modify a resource you can do so via its `self` URL (which it seems would be something like `/resources/4` in your scenario), or via a `related` URL (where a resource is in a 1-to-1 relationship).  
If you want to modify a collection, such as `blocks` in your example, the idiomatic URL would be something like this: `/users/1/profile/blocks` (assuming a user has only 1 profile, and that profile can have many related blocks).

> [@morris](#):
>
> I’m having a hard time understanding how relationships work from the documentation.

`self` refers to an associative entity / pointer, `related` refers to the resource (or collection) that is associated / pointed at by `self`. Modifying `related` changes the related resource (or collection), modifying `self` changes **which** resource (or collection) is related.

I notice you say:

[quote]the client only knows resource ids, not path-dependent relationship ids[/quote] In a REST API the client should not be generating any URLs itself (other than the initial URL to access the API); it should be following URLs provided to it by the API.

---

<div class="post-metadata">

**Author:** ![morris](https://avatars.discourse-cdn.com/v4/letter/m/d2c977/32.png) [@morris](https://discuss.jsonapi.org/u/morris)\
**Post date:** [August 3, 2016, 10:52pm UTC](https://discuss.jsonapi.org/t/implement-permissions-via-relationships/612/3 "2016-08-03T22:52:07Z")

</div>

Ok that makes sense, thanks for the confirmation on the relationships endpoint structure.

I understand now how `/directories/2/relationships/resources` takes resource ids:

[http://jsonapi.org/format/#crud-updating-relationships](http://jsonapi.org/format/#crud-updating-relationships)  
[http://jsonapi.org/format/#crud-updating-to-many-relationships](http://jsonapi.org/format/#crud-updating-to-many-relationships)

Assign `4 someone_elses_resource` to `2 my_directory`:

```
POST /directories/2/relationships/resources
{
	"data": {
		"type": "resources",
		"id": 4
	}
}

```

Assign `3 my_resource` and `4 someone_elses_resource` to `2 my_directory`:

```
PATCH /directories/2/relationships/resources
{
	"data": [{
		"type": "resources",
		"id": 3
	},
	{
		"type": "resources",
		"id": 4
	}]
}

```

Remove `4 someone_elses_resource` from `2 my_directory`:

```
DELETE /directories/2/relationships/resources
{
	"data": {
		"type": "resources",
		"id": 4
	}
}

```

Personally I feel that PUT should replace all of the resources in the directory and that PATCH should only insert the specified resources in the directory (leaving any previous resources in the directory alone). Otherwise there is no distinction between PUT and PATCH, which doesn’t make a lot of sense to me. However, a POST with an array payload can be used to insert multiple resources the way I was envisioning PATCH to work sparsely. So oh well THESE THINGS ARE HARD.

It sounds like if I want to operate on relationships using their ids, when only resource ids are exposed to the client, there is no way to do so under the current spec. Perhaps the JSON API maintainers could consider making `/directories/{directory_id}/relationships/resources/{resource_id}` an idiomatic JSON API URL. I understand that relationships must be promoted to first-class resources if they contain attributes, based on this response:

[https://github.com/json-api/json-api/issues/1042#issuecomment-217335990](https://github.com/json-api/json-api/issues/1042#issuecomment-217335990)

But I may have hit a use case where relationships have relationships to other relationships or resources, due to permissions and access control lists (ACLs). I don’t know if my need to hide relationships for permissions is a general need that REST APIs have or if I have just messed up somewhere. I feel like promoting my directory-resource relationships to first-class resources doesn’t make sense in this case because they don’t have attributes. But I’ve been struggling with this for several days so I’d be grateful for any outside ideas on how to solve this.

---

<div class="post-metadata">

**Author:** ![jlangley](https://avatars.discourse-cdn.com/v4/letter/j/9e8a1a/32.png) [@jlangley](https://discuss.jsonapi.org/u/jlangley)\
**Post date:** [August 4, 2016, 8:23am UTC](https://discuss.jsonapi.org/t/implement-permissions-via-relationships/612/4 "2016-08-04T08:23:42Z")

</div>

> [@morris](#):
>
> if I want to operate on relationships using their ids, when only resource ids are exposed to the client, there is no way to do so under the current spec.

If you’d said: “if I want to operate on **resources** using their ids”  
I’d reply: There’s nothing in the spec that prevents you from doing that. If you do then your API isn’t RESTful, but REST compliance might not be important to you.

But I’m not clear exactly why you say “ **relationships** ” here.

> [@morris](#):
>
> But I may have hit a use case where relationships have relationships to other relationships or resources,

Then I think you do need to promote your relationships to resources.

> [@morris](#):
>
> I don’t know if my need to hide relationships for permissions is a general need that REST APIs have or if I have just messed up somewhere.

Are you building an API to manage permissions on resources outside the API, or an API to manage resources which also allows permissions for those resources to be managed through the same API?

---

<div class="post-metadata">

**Author:** ![morris](https://avatars.discourse-cdn.com/v4/letter/m/d2c977/32.png) [@morris](https://discuss.jsonapi.org/u/morris)\
**Post date:** [August 4, 2016, 5:44pm UTC](https://discuss.jsonapi.org/t/implement-permissions-via-relationships/612/5 "2016-08-04T17:44:35Z")

</div>

The API will have public permissions endpoints so that a user can grant other users read/write access and also block them from both. I haven’t exactly decided on how the endpoints will look yet though.

Just FYI after thinking about this for a few days, I realized that I can set a permission on a public resource and even though users will still be able to see it if they look it up by id, the API can decide not to list that resource id in the relationships field. In other words, it can always use resource ids rather than relationship ids to infer when a relationship should be hidden. No need to map some notion of the unix executable flag for directory listing onto a relationship.

I think I was just overthinking it. Thanks for your help, hopefully this will help someone in the future.
