PUT Request showing in logs - rest

Not sure if I'm missing something here, but every site on RESTful design states that updates should be done via a PUT request. I've been doing that, but noticed that the parameters are being put in the URL (unlike a POST request) which means they will show in the logs.
So if a user updates their password, the plain text password will show in the log. This doesn't seem right. What is the proper way to do this?

I don't think that it is required for PUT to have params in the URL to consider it as restful.
You should have the following or something similar
HTTPS PUT /users/<userid>/password
Body: {password: abcd}

Related

REST method for validating credentials

I have a REST API, and I want to create a method that accepts a username and password, makes sure they're valid, and returns a user resource.
This is NOT to validate users of the REST APIs. The users are part of a separate system, and the API manages them.
What method and URL are appropriate for this?
GET doesn't seem like a good idea, since it would put the password in the query string. Plus this method might update the last-login-date on the user, so it's not idempotent.
I could use PUT, but I use that to update the user. So I could PUT to a different URL, but what would be an appropriate URL for this? Something like /user/credentials might imply that you're updating the credentials, not validating them.
The way I usually handle this is by performing a POST request to e.g. /user/login or simply /login.
You are basically creating a login attempt, therefore POST sounds reasonable, the same way as you can POST a search request.
By doing this you allow yourself to put the login credentials in the POST body, so they're not exposed in the url. And you are not updating the user resource, so you don't have to use PUT.
Example
POST http://example.com/login HTTP/1.1
{
"username": "Jon Skeet",
"password": "SOiscool"
}
You are POSTing the fact that the user needs a "user resource" to use "the separate system". POST is the only verb that is appropriate when a method isn't idempotent.
If "the separate system" is the only imaginable system the user will ever log on to, I'd choose a simple url like /user/login. Otherwise I'd add a path segment for "the user's relation to 'the seperate system'" like /user/theSeperateSystem/login.

Url's containing authentication secrets and app ID's

We received a request to create a REST api. I was a little confused in the example of provided by our client. As you can see below, they've identified the app_id and secret in the URL before the #. The remainder of the URI looks like what I would expect.
Is this valid? I thought maybe this is some weird cURL format I haven't seen before.
https://{application_id}:{api_secret}#api.example.com/entity/{entity_id}/
https://{application_id}:{api_secret}#api.example.com/entity/{entity_id}/entity_locations/{locations_id}/
Just seeing if anyone has seen this format before?
A URI is made up of various parts, one of them being the authority part, which can feature optional username:password element.
The full scheme is:
scheme://username:password#domain:port/path?query_string#fragment_id
This way your REST api remains stateless [not relying on previous app states like storing stuff in session]. But I advice you not to explicitly go with the username:password#stuff route, but to rely on Basic HTTP Auth, so the credentials are sent encoded in Base64 at least.
EDIT: a brief note about BasicAuth now you're asking - things go like this:
you make a request to http://johndoe:12345#service/api/foo/bar;
are credentials good? Ok, you get a 200 OK response with proper body;
are they not? You get a 401 Unauthorized response.
In the latter case, it's the browser [or any other program / script performing the request] that should prompt the user with the login popup.
Usually browsers ask you to cache credentials not to ask them every time, but this does not mean that they are not sent - it's just that every request to protected resources are featured with such header:
Authorization Basic base64encode(username:password)
Where base64encode is your custom way to encode the username:password string.

Correct REST response for "You must POST here before doing anything else"

We have a login REST service:
POST /sessions
When the users password has expired the next thing that must happen is that the client application will present a change dialog window and then change the users password via:
PUT /users/_ID_/password
What is the best way to communicate this intent to the client? At first I wanted to have POST /sessions return See Other (303). But this causes a GET on /users/_ID_/password. I could return a Multiple Choices (300) response which the client does not do an automatic get on, or I could return an OK (200) and tag in the JSON session object returned.
Having a look at the HTTP status code definitions, I'm thinking the following is the best fit:
409 Conflict
The request could not be completed due to a conflict with the current
state of the resource. This code is only allowed in situations where
it is expected that the user might be able to resolve the conflict and
resubmit the request. The response body SHOULD include enough information for the user to recognize the source of the conflict.
Ideally, the response entity would include enough information for the
user or user agent to fix the problem
There is a conflict with the current state of the session resource because the user needs to change their password before being able to create a session. You can return the url to the change password screen in this response so that the client knows where to go to fix the conflict.
At first I wanted to have POST /sessions return See Other (303).
This isn't correct. It would essentially be saying "Don't POST a session here, POST a session over there." You'd be relying on out-of-band information and hard-coded behaviour to recognise that this isn't the case and you should actually POST a new password there instead.
I could return a Multiple Choices (300) response which the client does not do an automatic get on
But you aren't offering multiple choices.
or I could return an OK (200) and tag in the JSON session object returned.
The POST wasn't successful, so you shouldn't respond with 200.
Are you really asking for the "correct REST response" or are you asking how to achieve a particular effect with HTTP? Because it seems you're looking for loopholes rather than the proper design.
If a request comes in and authorisation fails, then respond with 401 Unauthorized and a WWW-Authenticate header. Then use a custom authentication scheme that indicates the user needs to change their password.

iOS Development: When making a POST request, does it really matter if I include parameters in the URL?

I'm using the ASIHTTPRequest lib in my iOS app for making REST requests to a web app. I'm doing my best to use the correct verbs (GET, POST, PUT, DELETE) when making the various requests, but when making a POST request, I'm not sure I understand why it matters if I include the parameters in the POST request or in the URL. It works both ways, so why should I include the parameters in the POST request instead of just including them in the URL? As I understand it, the only reason for include the parameters in a POST request is to keep them from being visible in the URL in case someone is looking over your shoulder, or something like that. But if I'm making a POST request from my iOS app and there's no browser involved, then does it really matter which way I do it?
Thanks so much for your wisdom, I'm still learning!
When using a POST request, it is good practice to put the parameters in the data instead of the URL. In your case, it works to put it in the URL, but this isn't always true. Some scripts will expect the parameters to be in a specific place and not find them if they aren't there. As for what POST is good for, it allows you to send more data. The URL is limited to a length of 255 characters, so you need to use some other method if you want to send more data than that. The data in a POST request also doesn't need to be encoded to be compatible with the URL specification.
As I understand it, the only reason for include the parameters in a POST request is to keep them from being visible in the URL in case someone is looking over your shoulder, or something like that.
You misunderstand it.
There are other issues. If your site makes changes to data based off a GET request, it's possible that spambots, search engines, browser prefetchers, and other automated tools will trigger potentially destructive data changes.
If the endpoint isn't under your control, it's entirely possible that it won't even accept the parameters as GET parameters. Most APIs require proper usage of the GET vs. POST verbs.

Place API key in Headers or URL

I'm designing a public API to my company's data. We want application developers to sign up for an API key so that we can monitor use and overuse.
Since the API is REST, my initial thought is to put this key in a custom header. This is how I've seen Google, Amazon, and Yahoo do it. My boss, on the other hand, thinks the API is easier to use if the key becomes merely a part of the URL, etc. "http://api.domain.tld/longapikey1234/resource". I guess there is something to be said for that, but it violates the principle of the URL as a simple address of what you want, and not how or why you want it.
Would you find it logical to put the key in the URL? Or would you rather not have to manually set HTTP headers if writing a simple javascript frontend to some data?
It should be put in the HTTP Authorization header. The spec is here https://www.rfc-editor.org/rfc/rfc7235
If you want an argument that might appeal to a boss: Think about what a URL is. URLs are public. People copy and paste them. They share them, they put them on advertisements. Nothing prevents someone (knowingly or not) from mailing that URL around for other people to use. If your API key is in that URL, everybody has it.
It is better to use API Key in header, not in URL.
URLs are saved in browser's history if it is tried from browser. It is very rare scenario. But problem comes when the backend server logs all URLs. It might expose the API key.
In two ways, you can use API Key in header
Basic Authorization:
Example from stripe:
curl https://api.stripe.com/v1/charges -u sk_test_BQokikJOvBiI2HlWgH4olfQ2:
curl uses the -u flag to pass basic auth credentials (adding a colon after your API key will prevent it from asking you for a password).
Custom Header
curl -H "X-API-KEY: 6fa741de1bdd1d91830ba" https://api.mydomain.com/v1/users
passing api key in parameters makes it difficult for clients to keep their APIkeys secret, they tend to leak keys on a regular basis.
A better approach is to pass it in header of request url.you can set user-key header in your code .
For testing your request Url you can use Postman app in google chrome by setting user-key header to your api-key.
I would not put the key in the url, as it does violate this loose 'standard' that is REST. However, if you did, I would place it in the 'user' portion of the url.
eg: http://me#example.com/myresource/myid
This way it can also be passed as headers with basic-auth.