Is there a standard way to handle passwords within REST resources - api

Imagine we have a REST service that has a resource, that contains a password (or some other sensitive information). Once the password is set, we never want to return it through API (after it is set, only some external system will use it, we may be storing only hash of the password, etc).
So we have a PUT/POST request that sends in a resource with a password. What should GET request return? I could think of few possible solutions:
GET could return same resource, but without password field (Feels
strange, since password is a valid field for PUT/POST, so why not
GET)
GET could return resource, but with the password field empty or
set to some arbitrary value.
Have password removed from resource, and have a child resource.
e.g. resource/password, to which we can PUT password, but on which there is not GET request allowed.
This seems like a fairly common problem, but I cannot seem to find a good, standard way to solve it. Most of the search results point to actual passwords for users accessing the API, and resetting those, which is not the case here. Is there common, well-established way to handle this case?

You can POST/PUT data and not return it in the response or in a GET.
My choice would be #1 Return the resource without the field.
Also ok to use #2 and obfuscate the field.

Related

Is it possible to make the authorization header optional on an HTTP request?

So I am creating a forum website (like reddit). On a thread, I want to have two different ways of requesting the thread's comments from the backend.
One for if a user is not logged in.
One for if a user is logged in.
With the request for when a user is not logged in
I want to just return the comments with an:
upvoteCount value (for how many users upvoted the comment)
no userUpvoted value (or userUpvoted = null)
With the request for when a user is logged in
I want to return:
upvoteCount value
userUpvoted value (so the frontend can display if the user upvoted the comment)
The endpoint will be something like this:
GET /thread/{threadID}/comments?startIndex={start index}&count={number of comments to return}
For the user that is logged in, I will send the authorization token in the header.
For the user that is not logged in, I will not send the authorization token in the header.
Is it possible to make sending the authorization header optional to an HTTP request like this?
Or should I just make two separate endpoints?
Is it possible to make sending the authorization header optional to an HTTP request like this? Or should I just make two separate endpoints?
Yes, you can vary the representation (content) of a resource based on whether or not the authorization field is present in the request.
Is it a good idea? That's a harder question.
You already know how two separate resources works; there aren't going to be any significant surprises there.
We also have a standardized mechanism for indicating that multiple representations of a single resource are available.
But the Authorization field, specifically, is sort of a special case because of the role that field plays in access control; that has implications on how general purpose caches work, and therefore the Vary field that we use for indicating multiple representations has an exemption for the authorization field, etc....
If you submitted a single resource implementation like this for code review, I'd insist on a decision record as well, so that we have a permanent record of which trade offs we were considering (including, for instance, what's supposed to happen when Alice the Super Admin needs to verify the "anonymous" variation of the representation).

REST API URI Design for sensitive resources

I have an application backed by RESTFul API. The application have user management section through which an admin user can manage other users. One sample URI for one of the API operation endpoint is below.
Update User : POST https://example.com/api/users/user1
Here user1 is the Username of the user being edited by the admin.
Suggestion from the security side is to remove the username from the URI since it is sensitive info and since it is part of url it will be recorded in network logs. Solution suggested is to pass the username data in POST Request Body .
Moving the data to request body is fine. But if I remove the username from URI ,the URI will be like "**POST https://example.com/api/users**" . This clearly doesn't look like a valid REST URI. And my USER entity doesn't have any other unique property which can be used in the URI.
Is there any recommended way to form a proper REST URI in such a scenario ?
POST /api/users
This clearly doesn't look like a valid REST URI.
Sure it does.
REST doesn't care what spelling you use for your resource identifiers, so long as the spelling is consistent with the production rules in RFC 3986.
That said, there's no particular reason that the identifier for a document needs to include sensitive information.
There are a couple of possible solutions - if the client and the server both know the sensitive data, then you can use a hashed value, rather than a raw value, as part of your identifier.
That's not ideal: we have mechanical ways of communicating URI that accept parameters, but no standard that I know of for communicating that some value should be hashed first.
If code-on-demand is an option, you might be able to manage to instruct the general purpose client to hash the data before sending it.
Otherwise, I think you are reduced to communicating the hashing out of band -- imagine a web form that instructs the human being to type in the hashed value of the sensitive information.
REST is optimized for the use cases that it was optimized for, and that means that some other use cases are more clumsy than we might like. Hooray for trade offs.
One way is to use an "id" instead of "username":
https://example.com/api/users/{id}
where "id" is usually a UUID https://en.wikipedia.org/wiki/Universally_unique_identifier

Ignore or not API endpoint parameters based on access level

I am working on an API endpoint that returns a list of products:
"api/products"
The endpoint accepts the following parameters:
page_size
page_number
Each product has a boolean property named IsApproved.
In the web application used by common users I always want to return only the Approved products ... On the web ADMIN application used by administrators I want to return all products, Approved or Not ...
My idea would be to add a new parameter (enumeration) named:
ApprovedStatus
And the values would be Approved, NotApproved and All.
On each API call I would check the user permissions ... If is admin I will consider the value on this parameter. If not then I will always return only approved products.
Another solution would be to have different endpoints ...
Any advice on which approach to take or is there other options?
The approval status is part of the product, therefore, in a perfect REST world, you don't want a different endpoint at all since you're accessing the same resource.
Then, for filtering a resource based on a property value, I think the convention is that if you specify that property as a query parameter it will only return those matching the value, and if not, it will return all of them, so I don't see the need to define a special ApprovedStatus parameter with some special values. Just query by isApproved!
Finally, about how to handle authorization. This, I think, should be handled at a completely separate layer**. If authorization is involved, you should have an explicit authorization layer that decides, for a specific resource and user, wether access is granted or not. This means the query would be triggered and if one of the resources generated by the query fails to be authorized for the user that triggered the query, it's taken out of the results. This accomplishes the behaviour you want without having any code that is checking specific users against specific query parameters, which is good because if tomorrow you have another endpoint that exposes this objects you won't have to implement the same authorization policy twice. Pundit is a perfect example on how to do this with Ruby elegantly.
**Of course, this approach retrieves data from the database unnecessarily which could matter to you, and also opens your endpoint up to timing attacks. Even then, I would consider tackling these problems premature optimizations and should be ignored unless you have a very good reason.
You're right about your ideas:
You can create a new endpoint just for admins, that will return all products
You can use a kind of authorization (e.g. Authorization Header) in order to check if the API is being called through admin or normal user. Then you can route internally to get all products or just IsApproved products.
You can add a proxy in front of your API to route to the right action, but it can also be achieved directly in the API but I think the second solution is easier.
Adding one more property is a bad idea.
In my opinion, adding another end point is very good. Because it will increase the protection in the admin end point.
Otherwise, since it is a web application, Simply set a cookie and a session to identify and separate the admin and user.
Going with the principle of least astonishment, I'd be in favour of adding a second endpoint for admin users. Such that you'll have:
GET /api/products (for regular users)
GET /api/admin/products (for admins)
This allows your code and API documentation to be nicely separated, and all of the admin-specific authentication details can live under the "admin" namespace.
The intention behind each API call is also clearer this way, which helps developers; and means that you can differentiate between admin vs regular usage in any usage stats that you track.
With ApprovedStatus, I think the specifics here don't matter much, but - considering what a developer using the API might reasonably expect / assume - it would be good to:
Ensure the ApprovalStatus parameter name matches the property name for "approval" that you return with each product object
Defaults to "approved" if it is not specified
Alert the user when an invalid value is specified, or one that they don't have access to
Bottom line: to answer your headline question - I think it's bad practice to ignore user input... sometimes. Design your API such that distinctions around when input can be passed in is very clear; and always alert the user if you receive input values that are technically acceptable, but not in the way that the user has requested, or for their access level. Ignoring values that are plain wrong (e.g. an argument that doesn't exist) is another story, and can be useful for future proofing or backwards compatibility.

Add instruction 'how' to perform a REST API request by adding header or body param?

Imagine a simple REST API that allows to create a user account, by sending a JSON resource to POST /users as in the following. By default it sends out a confirmation email to the user.
{
"username": "john#appleseed.com",
"password": "secret"
}
However sometimes there are good reasons for not sending out a confirmation based on the use case, e.g. another API client, or admins signing up users on their behalf.
Since it doesn't have any implications on the created resource but is more of an instruction how to create the user, should it be separate from the request body? What's the best way to do this?
Specify a custom header Confirmation: no-confirmation
Add a query param ?confirmation=false
Add a send_confirmation field to the request body
Let's take the options in order:
Adding a header value to indicate some semantic difference should be generally avoided. The API should be "browseable", meaning it should be discoverable following links only.
Adding a query parameter is, from REST perspective completely equal to creating another URI. It does not really matter how you expose it, the point is that the client needs to follow some links from the previous "state" it was in. This is actually ok, as long as the links to these resources indicate the different semantics you described: like creating users by admin, users creating themselves, etc.
Also note, that the API should not necessarily expose whether a confirmation is sent. The API should expose the "purpose", the server then can decide whether the use-case warrants a confirmation email.
Putting a send_confirmation in the JSON representation itself. This is ok, if this is a functionality available for the user. For example I can ask for a confirmation email. If I can't, and it is only used for differentiating different use-cases, then I would rather prefer option 2.
Summary: For the case you are describing I would pick option 2: different resources for admins and normal users.

RESTful way of having a single resource based on authentication

I have an API that provides an Account resource based on the authentication (login) that is supplied. As a user can only have one account, and can only see it's own account and not those of others, this API will basically be a single resource API in all cases.
So to keep things simple, I have this resource under the url accounts/ and when you access accounts/?username=dude&password=veryhard you'll get your account data (if you dohn't supply authentication you'll get a 403).
Now I wonder if this is RESTful. Also, you should be able to update your account info, and I wonder if PUT would be appropriate. In my knowledge, PUT should be done on a unique URI for the resource. Well, is this a unique URI for the resource? Generally a URI for an account would look like accounts/3515/ where 3515 is the account id. However, users don't know their account id. Also, there should be more ways to log in, instead of a username + password you should also be able to use a token (like accounts/?token=d3r90jfhda139hg). So then we got 2 URL's that point to the same resource, which also isn't really beautiful for a RESTful URI, is it?
So, what would be the most RESTful solution? Or should I not do this RESTful?
REST purists will consider that use of /accounts/ to obtain a single account is bad practice as it should specify a collection. Instead consider a key which cannot be mistaken for an ID, for example if your IDs are UUIDs then use a token such as 'me' so your URL is /accounts/me. This has the advantage that if later on you wish to obtain different account information, say for example you need to list users or you have an administration system using the same API, then you can expand it easily.
Putting username and password in the URL is also not pure REST. The query parameters should be directly related to the resource you are obtaining; commonly filtering and limiting the resources returned. Instead you should seriously consider using something like HTTP Basic authentication over an encrypted (HTTPS) connection so that you separate out your authentication/authorisation and resource systems. If you prefer to use a token system then take a look at oauth or hawk.
Finally, yes if you use PUT you should supply a full resource identifier. Given that it is very common for systems to read data before updating it the lack of ID won't be a problem as that will come back as part of the prior GET.
Yes accounts/?username=dude&password=veryhard is a correct REST URL.
PUT is used with an id if it used to update a resource, if you use it to create you must supply an ID. otherwise you use post to create a resource without id