Imagine I have 2 routes in my application:
POST /login -> {token: some_token}
route for authentication that returns token for accessing second function
POST /divide -> {result: x / y}
route for simulate function divide(x: int, y: int), that protected by token bearer from first route. Also in this function I have some validators, i.e. x and y must be integers, y must be not equal 0 and it returns 400: BadRequest if one of those criteria is failed
So, my question is, if user didn't provide token bearer and parameters for route /divide, should I return 401 or 400?
There're two things that concerns me
return 400: user can figure out my API structure by sending
empty body and parse response, like send empty body and get {x: must be provided, y:
must be provided}, then send x=abc,y=bca and get {x: must be integer,
y: must be integer}, etc...
return 401: user can DDoS my application by sending a lot of
random tokens, so for each request application should check storage if token valid or not
What is the best practice in that case?
Thanks.
Without authorization you should in no way process any of the other content. Else, why have authentication/authorization at all? If you do process the content while the user is unauthorized you basically have a security breach. Obviously for the example function that does not seem like much of an issue, but that is the gist of it.
So you should return 401.
In case of the DDoS problem, that is not solved by processing in different order, you would still have to check all the tokens. And even if you did not someone could DDoS your service/API. There are other (API Management) solutions for that, like throttling, white-listing, rate-limiting etc.
Well, it looks like "opinion" question but i'll answer.
You need to return 401, becouse authorization is first thing you should do. Only if user can access resource, we can continue process.
Related
I struggle to find the good way to respect the REST principle for an http endpoint:
I should define an endpoint who will check that a complex form object fill a few conditions and return the list of the unfilled conditions. (no change in the database will be produce by the endpoint ). Basically it's a validator
POST .../myComplexForm/validate-myvalidationCase
Request: myComplexForm{field1: int, field2:int ....}
Response : ??????
What is the proper way to define this response-bject respecting REST ?
The endpoint can find in the object more than one error and should return all of them, not just one ( It's not a validation field by field. More a "you are not allowed to have more than XXX if it's Sunday and you are YYYY)
What should the endpoint return?
a list of error?
Throw an http exception containing the list of error?
A response object with a
field by error? then what will be the http code?
Thanks !
If the purpose of the endpoint is to receive any object, and return whether the object was valid or not, then in my opinion sending an invalid object is not really an error.
An error should tell a client, 'you should stop doing that', or 'you should change something about your request and try again', but in this case the explicit purpose is to also report invalid sates.
So if the object was invalid, I would still probably return a 200 OK. I don't really have an opinion on what format your result should be, as it depends on what the goal is of this feature. You should return what the client needs.
I've generated Access Tokens in the Settings/..../ Keys and Access Tokens page and now have a
Consumer Key
Consumer Secret Key
Owner ID (even though this was probably already generated)
Access Token
Access Token Secret
and am using a rest client to test being able to pull the latest 3 statuses using this api end point
https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=userIdHere&count=3
as well as the following headers
Accept: /
Connection: close
User-Agent: OAuth gem v0.4.4
Content-Type: application/x-www-form-urlencoded
Content-Length: 76
Host: api.twitter.com
Authorization: OAuth
oauth_consumer_key=
oauth_signature=
oauth_signature_method=
oauth_timestamp=
oauth_token=
oauth_version=
obviously the 'userIdHere' in the end point address (above) is substituted with my username (i know i can also use my user_id, but that's beside the point) as well as the 'Authorization' values being substituted for real values. That's where my question lies...
What is the mapping for each of the 'oauth...' authorization parameters to their associated Twitter generated and provided Token or key(s) (which were mention near the top of the post)?
I keep getting a '400 Bad Request' response and feel that it is the authorization that is failing in that the permutations of key placements is incorrect. I do not know which value goes to which 'oauth...' value
finally, the structure of the 'Authorization' parameter header is as follows (as per instruction here from the Twitter EXAMPLE) as one line string value
OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog", oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1318622958", oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", oauth_version="1.0"
)
I am just trying to use a GET to get the last 3 statuses and have not been able to. Also, i plan to switch the values to Environmental Variables, but that doesn't matter yet..
UPDATE
using Postman now, and it's better at mapping, but now am getting
{
"errors": [
{
"code": 32,
"message": "Could not authenticate you."
}
]
}
For the Postman part make sure that you leave Timestamp and nonce empty and hit "update request" before you hit send. That will generate timestamp and nonce - otherwise you will get authorization failures every time. I just tried it with my twitter API credentials and it works.
For Oauth gem code, I find it strange that you have a Content-Type and a Content-Length header for a GET request. Looks like the 400 Bad request could be because you are attempting to do a POST to an endpoint that only supports GET. Indeed when I try to do a POST to that endpoint it tells me.
{
"errors": [
{
"code": 86,
"message": "This method requires a GET or HEAD."
}
]
}
So the 400 is actually good news - it means that authorization works, you are just calling the API in the wrong way.
I am currently writing an REST API using the Jersey Framework. I am following the HATEOAS principle and the user should only be moving through the api by the given links in my response body oder headers. On some Resources I have implemented pagination functionality. I was wondering though, what should I tell the User (HTTP Status Code), when he is not following my boundaries and just like randomly makes a request where the requested page is actually "out of bounds". Currently I just return a null Collection, but I think as a User, I wouldn't be able to make something out of such a response. I considered using the Status Code "Not Found", but I am not sure if that is the appropriate one. I really want to stay true to REST and that implicates I stay true to HTTP. So can anyone give me suggestions or even tell me if there is actually a rule for my problem?
Maybe a concrete example:
page size = 10;
Collection.size = 27;
requested page = 4;
Paging starts with page 0
, so requesting http://...../resource?page=0, returns the first page.
My question is, what should I return for the request http://...../resource?page=4? Currently I am just returning null, but I don't think that's the proper response.
Thanks in advance
EDIT:
I am only asking about the expected Response in case the requested page is "empty". I know that fixed page size design may be doomed for future change requests, but since this API is part of a Microservice, there will be none, except we have a fight inside our team :)
404 not found is the appropriate return code for an out of bound access.
But you should consider change your resource identifier (URI). Returning 404 or 200 depending on a URL parameter is not a good design.
It would be better to treat every page as single resource. That's also true for HATEOAS.
.../resource/page/0 #200 + return link in header to next resource .../resource/page/1
.../resource/page/4 #404 + return link to first resource .../resource/page/0)
Using URL parameters should be the last option if nothing else works (for example range access).
The following code should post a form to an endpoint (which returns 302) and, after following the redirect, parse the url of the page and return some information from there.
val start = System.currentTimeMillis()
val requestHolder = WS.url(conf("login.url"))
.withRequestTimeout(loginRequestTimeOut)
.withFollowRedirects(true) //This appears to have no effect...
requestHolder.post(getMap(username, password))
.map(resp =>{
Logger.debug(resp.status.toString)
val loginResponse = getResponse(resp)
val end = System.currentTimeMillis()
Logger.debug("Login for the user: "+username+", request took: " + (end - start) + " milliseconds.")
loginResponse
})
The problem is that .withFollowRedirects(true) appears to have no effect on the query. The status of the response is 302 and the request does not follow the redirect.
I've gone through the process manually using httpie and following the redirects does lead to the correct page.
Any help or insight would be much appreciated.
POST redirection isn't as well supported as GET redirection. W3 specification says:
If the 301 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
Some browsers don't do that, and just ignore. Have a look also at the 307 status:
307 Temporary Redirect (since HTTP/1.1)
In this case, the request should be repeated with another URI; however, future requests should still use the original URI. In contrast to how 302 was historically implemented, the request method is not allowed to be changed when reissuing the original request. For instance, a POST request should be repeated using another POST request.
There is also a discussion about this on Programmer Stack Exchange.
I've had a lot of trouble with withFollowRedirects and POST.
At some point, while fighting to make things work, I had .withFollowRedirects(false) in my code, then removed it during cleanups & things broke. My current guess is that if this option is not explicitly made false, the default behavior is to follow redirects (302 in my case) with some faulty mechanism. Perhaps the default mechanism uses POST again with same arguments. But in my case, interacting with Google App Script (GAS), one needs to use GET to retrieve JSON output of a POST.
Whatever the mechanism was doing, I was getting 400 with no further diagnostics.
After wasting hours, I realized that .withFollowRedirects(false) was in fact truly needed: it disabled Play's messing with redirects, I was able to see the 302 response & handle the following GET manually with success.
I have to define an API that answers whether a resource with given ID can be created, like
Can I (caller) create this resource with id=resource1 ?
The possible responses could be
401 - The caller is not authenticated
403 - The caller is authenticated but not authorized to perform this check
200 - Yes, you can create a resource with id=resource1
...
Now my questions are
How can I model the API?
Will, GET /resources/resource1 be a good choice?
What HTTP codes will suite for responses like,
(a) this resource id is already taken, (b) you don't have permission to create this particular id (but only few other ids), (c) you can create this id.
An example in github may help you.
The api designed for checking if a user is following another user:
GET /user/following/:username
The deal information is presented in github's api document
For your question1, I think you can implement like this:
GET /resource/existence/:resource_id
For question2, you may also take a look at github's client errors
Would it be better to just try and create the resource with a POST? and let your implementation handle the response from there? In which case your responses could be:
a) 409: Conflict
b) 401: Unauthorized
c) 200: OK
If that's not possible, then I guess your payload response from a GET can contain the result. Something as simple as:
true: You can create the resource
false: You cannot create the resource
Since you want to check the permissions regarding the addition, you should use a different resource than the one that actually added the element. IMO something like /permissions/{elementName}?id=theid or /permissions/{elementName}/{operationName}?id=theid. Accessing it with method GET would suit.
Using the same resource would be a bit "messy" I think since I would expect the method GET on /resources/resource1 to actually return the content of the element with identifier ressource1.
Regarding the response, I would see this:
401 if the user isn't authentication and the permission resource requires an authentication.
204 if the current user is allowed to add an element with the specified identifier. I don't think that you need a response payload in this case.
Regarding the case when the user isn't allowed to add an element with the provided identifier, I think the status code 403 (Forbidden) suits. Perhaps a status code 400 could also match if you consider that the user provides a wrong content. In this case some hints about the error (identifier value not allowed) should be returned within the response payload.
For me, the status code 409 (Conflict) is more when implementing optimistic locking, i.e. concurrent accesses (updates) on the same element.
Hope it will help you,
Thierry