REST API - How should I store a record of an user accessing/viewing a resource? - rest

Say I have two resources, users and items, for example,
api/users
api/items
I want to store a record of when an user access an item (which items has access each user). What would be the correct way to do this in a REST way.
I could do something like this
POST
api/items/1
{an userId}
instead of GET request and retrieve the item and create the view record. Or using a GET request on api/items/1 and then relying on the client to call another api method to add a view record. But those ways just don't feel right.
Is it a recommended way to do something like this in a REST way?

I'm curious as to why you want an auditing function like storing who viewed the record to be an external REST API call...
I would think the simplest REST API would be to make the access a GET request like https://{url}/api/items/{id}?token={something_from_authentication_call} assuming that you've authenticated the user and provided them a token to use with all calls.
Then, since you're internally maintaining a token-to-user association somewhere, have the backend service either write the auditing data directly to a database, or call some other internal service not exposed to the outside world to create the auditing data.

Don't you use authentication before calling your REST? Usually user authenticates before and when the REST is called you know who is calling.
If you don't have authentication you can use any method of passing user as body parameter or as request header.

Related

REST API and ETag on individual resources of a list

Considering I have a REST API exposing a repository of users :
/users/ -> returns an array of UserModel
/users/{Id} -> returns a UserModel
I needs to implement a client application that support offline mode (API not available) that will display the list of users and the detail of each user.
I am considering to synchronize in the client app the users this way :
Get the full list of users by calling a GET on /users/ and persist the list of users
Each time a user is accessing a user profile, if REST API available, check if the user has been updated by calling the REST API and update the user details if necessary
Display the user profile
I am considering using ETag (https://en.wikipedia.org/wiki/HTTP_ETag) to implement this behavior.
My issue is that I don't want my client application to get user details one by one by calling GET /users/{Id} but in a bulk by calling GET /users/ (with some paging if needed). If I do so, the client application will get a global ETAG of the list of users, but not ETags of each user. Thus it will not be able to verify individually if a user entity is up-to-date.
As a workaround, I am considering to add an ETAG field to the UserModel of the API. This way after calling GET /users/, the client app will be able to check if a specific user has been updated by calling GET /users/{Id} with the If-None-Match <User'sETagValue> header.
I know that the solution do no stick to he HTTP 1.1 standard, and that it adds a little complexity to the ETag generation.
However, I can't find any other post describing such a solution and I am wondering if it presents major issues ? And If there are more elegant solutions ?
Thanks for your help,
Edit : WebDav standard defines a "DAV:getetag" property that looks similar to my approach (http://www.webdav.org/specs/rfc4918.html#cache-control)
The WebDAV spec is also the first thing that came to mind for me.
I don't see an issue with adding etags to the response of your collection. You might even define a collection in a more general way, so that the format is just a list of URIs, their responses and headers so your client can treat it as a list of resources that need to be written to a cache.

Can I send access token using GET method?

I'm building RESTful API, but I have some question while implementing /valid
endpoint.
/valid endpoint checks token expiration.
Is GET method good choice for this endpoint?
Is there any problem with sending token using GET method?
(like http://some.api/valid?access_token=ACCESS.TOKEN.STRING )
If you use GET, your server log will be full of access tokens. This may be a security issue to consider.
What you're doing is essentially RPC, passing a parameter (access token) into a function (validate).
To do it using REST, you could consider the resource as the access token. As you have it, it's already been created (POST) so you would want to interact with it in some way. PUT updates a resource but you're not updating but you're not using REST either so it doesn't really matter. You could use POST but as I said, the resource (access token) has already been created.
So to get as close as possible to REST, you could:
PUT /accesstoken/validate
body: ACCESS.TOKEN.STRING
and get a suitable response. It also allows the server to track whether the access token has ever been validated, if that's of relevance. As it's RPC, it means the server could do other things that may update the resource in some way. i.e. number of times it's been validated and the ip address it was validated from, increasing security perhaps.

Capturing audit trail information via REST

I'm struggling with coming up with the "right" way to capture audit information via a REST service. Let's say I've got an internal REST API for an Employee resource. I want to capture things when an Employee is added/modified/removed such as the user who did the change, the application the user was using, when it was done (assume this could be asynchronous so the user's action may have taken place at a different time than the REST call), etc. Also, the user that initiated the change may not be the authenticated user making the REST call.
My thoughts are that those properties do not belong in the body of the request - meaning that they are not attributes of the Employee object. They are not something that would be retrieved and returned on a GET, so they shouldn't be in the POST/PUT. They also do not belong as a parameter because parameters should be for specifying additional things about Employees or a search/filter critiera on GET requests for Employees.
My current thoughts are to have the client specify this information in the HTTP headers. That keeps the URL parameters & body pure for the Employee resource. Is that an appropriate use of the headers? Are there other options that I'm not seeing?
I'm working on a project with a very similar problem, and we did end up using HTTP headers to track auditing information. Actually, this was a byproduct of requiring an Authorization header which specifies the client user and application, and we use this information inside the REST service to store details in an audit log.
In your case, I don't think it's "wrong" to add custom X headers to specify the original user/application/time the request was made and storing these to an audit history in the service somewhere. Basically proxying on information via extra request headers. I also agree that these should not be part of the request body or URL parameters.

RESTFul API endpoint design with filtering and authorization

I am designing a REST API with consumers that have different permissions. I understand that a representation of a resource should not change according to user. Therefore I am trying to determine which is the best approach:
GET - list collection of all documents - admin only.:
/api/documents
GET - list collection of all documents - any user with access to document 123
/api/documents/123
For normal users therefore should the endpoints be
list all documents for user 12
/api/user/12/documents
document 123 assuming user 12 has access
/api/documents/123
OR... should the end points be as below and a query string filter used:
/api/documents?user=12
/api/documents/123
In this case you can get away with just two endpoints (and one header!). Make sure the API for /documents is returning the Vary: Authorization header. Then you can use
GET /api/documents // return all docs the logged-in user can see
GET /api/documents?userId=bob // return all of bob's docs that the logged-in user can see
GET /api/documents/123 // return doc 123 if the logged-in user can see it
It is not entirely unreasonable to nest the user a la GET /api/users/bob/documents. I find it to be harder for end users to learn APIs with a large number of endpoints, and I feel that the nested approach tends to create many endpoints. It's conceptually easier to go to /documents and see what you can filter on, rather than look at each endpoint and see what filters it has.
I would keep business logic and authorization logic entirely separate. If you want to retrieve document XYZ, you wouldn't pass the user id as an HTTP parameter.
You suggested /api/documents?user=12 but in fact it should just be /api/documents. The user information should come from the authentication layer.
Similarly authorization should be entirely separate. The reasons for that are:
separation of concern
ability to update authorization logic independently of of business logic
avoid impact on API design
The API should only reflect those business objects you care about e.g. documents in this case (possibly also users should you wish to display a user profile...).
To handle authentication, use the container's standard techniques (e.g. HTTP Basic authentication) or use advanced authentication techniques (OAuth..) via a dedicated framework.
To handle authorization, use a filter, an interceptor. In the Java world (where JAX-RS implements REST), have a look at the Jersey interceptors and filters. You then want the interceptor (or policy enforcement point - PEP) to query an external authorization service (or policy decision point).
Have a further look at ABAC, the attribute-based access control model, and XACML, the eXtensible Access Control Markup Language which explain how to control access to your REST APIs without mixing business logic and authorization logic.

What is the best way of passing user info/profile/context via web API service

I am a newbie who is writting ASP.Net web API service for the very first time. The issue I am having is how to pass user information or different contexts via service request. For example I want to pass user context (i.e username, user preferences etc.) and lets say security context (i.e. api key, secret etc.) thru each service call. The options I found
1. using Query string
2. custom HTTP headers
3. overload authorization header to pass Jason object
4. cookie
I ditch the idea of using query string as it has 2k limitation, custom header could be ripped by proxy services, dont want to use cookie,creating a jason object of all the context and send it via auth header can work but seems like not a smart way. Any idea? what is the best way of passing those extra information.
I really appreciate if someone help me with some examples.