I want to understand how to deal with authorization in REST API with endpoints like below
GET /resource/:idDELETE /resource/:idGET /resource
Assumptions
- User Bob is authenticated.
- Bob only owns resources with id
1,2,4,5,6but3 - System has an Access Control and Busines Logic Layers
- The business layer doesn't have any awareness of data ownership
- Access Control Layer has
policiesforresourcesandusersand it can check if users have the right to access resources and reject the request withHTTP403or pass it to the Business Logic layer to be processed
Scenario
- Bob sends a request to
GET /resource/2, the application returns resource details withHTTP 200 - Bob sends a request to
DELETE /resource/3, and the application returnsHTTP 403. - Bob sends a request to list resources
GET /resources?page=1&pageSize=10, the application returns resource summaries of1,2,4,5,6but3
Problem
The Access control layer can prevent(403) access to a specific resource by checking the claims of the user for a given resource with defined policies. But It should not be PREVENTED(403) when accessing search endpoints. It should be FILTERED.
Approach 1
- It may assumed that search would include summaries of resources that is not owned by the authenticated user.
Approach 2
- Search endpoints may be entirely separated and have the awareness of resource ownership and have the responsibility of resolving ownership and filtering.
- Other endpoints stay clean by having only business logic.
Questions
- Which alternative approach is better?
- Is there any alternative?
- Am I mixing concepts of data ownership, access control, and business logic?
I think you are mixing these concepts. Let's start from the very beginning:
If a particular user, in this case Bob, is authenticated and his authentication records have policy which defines access to a particular set of resources ( or defines prevention of access to particular set of resources ) then that status should be PREVENTED. Why?
Bob is PREVENTED from accessing particular resources. FILTERED means filtering data and that's something that you can do even when Bob has access to the data. When Bob receives 200 OK status with records that he wanted, internal functionalities of the API can still filter the data that will be adapted to the policy Bobs authentication records hold.
If in our database we have set of records like this: [1,2,3,4,5,6,7,8,9,10] And we want to create policies that will prevent some users from access a particular record then we can have policies set up in the way where we describe records that define access a particular user has. On example policy can define a record that holds number 3 in a array (
[3]) and based on this we can create a logic that would obviously filter out the data that's in the array and return[1,2,4,5,6,7,8,9,10].However, this model heavily depends on how your data is structured. Questions you might want to ask yourself before designing your policy records:
<COLLECTION/TABLE_NAME>:<ACCESS_LEVEL>which would in this case yieldnumbers:*ornumbers:[1,2,4,5,6,7,8,9,10].access_needed: [ "read", "write" ]Again, it all comes down to your records and based on that you can structure how to define your policy format.