12

The question pretty much covers it. Given a RESTful API where we have multiple resource types and various user permissions around who can CRUD them, are there any established best practices for exposing those permissions to the front end so that the permissions don't have to be stored in two places?

I have a pure JS application and I need to know when to, for example, display edit and delete links for a given resource. I would like a standard way to make these decisions based directly on the ACLs stored on the backend. I considered maybe bringing back an ACL portion in the REST envelope for all GET responses, but I was hoping maybe someone knew of an established best practice.

For what it's worth, I'm also using Symfony2 and its security component.

Jason McClellan
  • 2,931
  • 3
  • 23
  • 32

1 Answers1

13

In a purely RESTful scenario, the client wouldn't manage an ACL at all. Rather, as the client requests information, returned resources would include links from those resources to possible links the client could follow. That way the server is telling the client what can and cannot be done with the given resource (specific to who is requesting it).

Example: your JS client retrieves a JSON payload for an item which has been purchased but has not yet been shipped. The client might receive a payload that looks like this:

{
  "name": "Gadget 1",
  "price": "16.99",
  "status": "ORDERED",
  "_links": {
    "details": { "href": "/item/a631723d69/details",
                 "method": "GET"),
    "cancel-shipment": {  "href": "/item/a631723d69",
                 "method": "DELETE" }
  }
}

Because the server returned the cancel-shipment link relation, it means that the item in the order is allowed to be cancelled at the present moment. But imagine what the resource might look like after it's shipped and the request is made several days later:

{
  "name": "Gadget 1",
  "price": "16.99",
  "status": "SHIPPED",
  "_links": {
    "details": { "href": "/item/a631723d69/details",
                 "method": "GET")
  }
}

The cancel-shipment link relation would no longer be returned from the server, because it's no longer a permissible operation (i.e., you can't cancel an order after it's been shipped).

More traditional access control can be managed in the same way (i.e., don't send the cancel-shipment link to a user who isn't authorized). Suppose the order hasn't shipped yet and your spouse can see what it is you've ordered but is not allowed to cancel it. They'd get this back:

{
  "name": "Gadget 1",
  "price": "16.99",
  "status": "ORDERED",
  "_links": {
    "details": { "href": "/item/a631723d69/details",
                 "method": "GET")
  }
}

So in summary, the links returned in each response encapsulate and represent what the requestor is authorized to do at any given moment in the system.

In any case, you must check for appropriate authorization on the server for the request being made, as you never know when someone may be hacking around with raw URLs.

Jonathan W
  • 3,759
  • 19
  • 20
  • Ahh, this is a great point. I hadn't thought about basing the client strategy solely on the links returned. It's rather obvious in hindsight.. Thanks! – Jason McClellan Oct 21 '13 at 16:05
  • @Jonathan W: Along the same lines, do you think it would be valid to modify the actual structure of the Order object depending on the permissions of the authorized user? For example, if my wife can see what I've ordered, but SHOULDN'T see how much I paid for it, do you think it would be valid to return the order object without the price property? – MajorRefactoring Apr 04 '14 at 10:16
  • What do you mean by "the actual structure of the Order object"? Do you mean return a different representation of the Order resource depending on who you are? You could do that, but keep in mind that's going to mess up your ability to cache resources effectively. (And, as has been pointed out to me, so will my answer to this question.) – Jonathan W Apr 04 '14 at 17:04