Amazon API Gateway - Gateway Responses Ordering - amazon-web-services

I have setup my API at Amazon API Gateway and the Gateway Responses part seems to be a bit confusing.
There are a lot of default responses defined here along with the HTTP Return Code:
Access Denied (403)
Invalid API Key (403)
Invalid Signature (403)
Missing Authentication Token (403)
Unauthorized (401)
Is there any logic of which response is returned upon which condition? I have done my tests and I wasn't able to find a pattern.
No API Key + Valid URL: Invalid API Key
No API Key + Invalid URL: Missing Authentication Token
Good API Key + Invalid URL: Missing Authentication Token
Is there any specific pattern here?
Thanks,
Guven.

As noted in comments, for security reasons, API Gateway can give you the impression that it is really pretty obsessive about these mysterious authentication token thingies, whatever exactly they may be.
But this was apparently done because it should be difficult for a malicious user to determine a specific reason why the request is forbidden... and, as you have discovered, this message is as potentially uninformative as it is potentially misleading. (Not necessarily a criticism, here... that's what it's for.)
What you'll probably find helpful is to go in and customize your error responses and change the default wording of each message to match its actual meaning. There are several where you'll find Missing Authentication Token in the text of the template.

Related

Does AWS Cognito Token endpoint origin have to match Auth endpoint origin?

I am using AWS Cognito federated through Google.
I am trying to use the Authorization Code Grant flow, which requires making two requests.
/oauth2/auth
The first request is to get the authorization code, which is then sent as part of the second request. This request comes back fine.
/oauth2/token
This request accepts the authorization code from the first, and should return the appropriate tokens.
However, this endpoint requires a secret in the header, so I have created an API (to not expose the secret to the client) that accepts the token and makes the request from a different origin as the first request. For example, the first request is made from example.com, while the second is from api.example.com. This fails with the error message: 400: invalid request. But, if I take the exact same code from the API, and put it in the client directly (with the secret), it returns the appropriate tokens. The only difference I can think of is the origin. Is there a way around this or is this just not possible?
Thanks in advance.
Nevermind, forgot to stringify the data as part of the request on the server-side. Thanks.

Reactjs app making requests to Django which exists on different domain

I'm trying to make a request from my reactjs app existing on "localhost:3000" to my django living in "localhost:8000"
I was expecting some authentication token in header to passed along with the request, but it's not the case. The request seems to be stripped and the token is nowhere to be found. Unless I pass the token in the url as a parameter (which exposes the token that can be decoded. I don't like it), I can't seem to be able to get the token in any way.
so my questions:
is this CORS issue? My understanding is that CORS usually deals with javascripts only, and Django already has the middleware to deal with this.
I'm currently using a GET as method. Does using a POST help in this case? How would the reactjs script be written? Currently it's just a href attached to a NavItem
and ultimately:
How do I pass the token from reactjs to django?
We can perform the implicit grant on the front-end and then configure the Django API in Auth0 and specify its identifier in the audience parameter. This would grant you an access token which you could then use against your API. Your API would then verify the token and check the audience is correct. (This has a good overview of the process https://auth0.com/docs/api-auth/grant/implicit and then with the API https://auth0.com/docs/architecture-scenarios/spa-api)
Basically what we can do is when Auth0 authenticates the user it redirects the user to the app with an access token, and optionally an id token, in the hash fragment of the URI. We can extract that and use the token to call the API on behalf of the user.
So, after we have [created the API in Auth0][3, [defined the endpoints]3, and secured the endpoints we can call the API (by sending the access token in an Authorization header using the Bearer scheme).
If you have any Auth0 specific question please feel free to join over in community.auth0.com you may have better luck finding help/solutions.
The 403 error is telling you that the request is not being processed because something is stopping from process that request 403: The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated
As you said probably because the CORS, try to follow the guide bellow of how to install Django-cors
https://github.com/mbrochh/django-graphql-apollo-react-demo#add-jwt-authentication-to-django

AWS Chalice Unexpected Behavior

I am writing a Chalice deployment, and experiencing behavior that I cannot explain.
My root endpoint accepts PUT requests, and verifies some basic authorization credentials.
from chalice import Chalice
from base64 import b64decode
app = Chalice(app_name='test-basic-auth-issue')
#app.route('/', methods=['PUT'])
def index():
auth = app.current_request.headers['Authorization'].split()
username, password = b64decode(auth[1]).split(':')
if username == 'test-user' and password == 'test-password':
return {username: password}
else:
raise Exception('Unauthorized')
Using curl to interface with this API:
curl https://test-user:test-password#<API-URL>/dev/ --upload-file test.txt
I get the following response:
{"message":"Authorization header requires 'Credential' parameter. Authorization header requires 'Signature' parameter. Authorization header requires 'SignedHeaders' parameter. Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header. Authorization=Basic dGVzdC11c2VyOnRlc3QtcGFzc3dvcmQ="}
However - when including any parameters in the URL:
curl https://test-user:test-password#<API-URL>/dev/?ANYTHING --upload-file test.txt
I get the expected response of:
{"test-user": "test-password"}
I'm not sure why specifying parameters is effecting the Authorization.
I have no inside information, so I have no way of knowing whether the following is actually correct, but this seems like a reasonable explanation for the behavior you're seeing.
AWS APIs generally support two alternatives for supplying your credentials: query string parameters, or the Authorization: header..
To the layer in their stack that checks the Authorization: header, your value seems wrong, so they throw an error, since your supplied credentials are not in the correct format...
...unless it sees a query string in the URI... in which case, it could be choosing to allow the request to proceed, on the assumption that the authorization might be done at that layer.
So the request is handed off to a different layer, which is responsible for query string handling. It doesn't find any credentials in the query string, but it is also aware of no credentials having been found while headers were being processed, previously, so the request is processed as an anonymous request if those are allowed.
So, you're slipping through a hole: by adding a query string, any query string, you prevent the Authorization: header from throwing the error.
It's not a security vulnerability, in my estimation, but rather a case where something in the URI changes how headers are interpreted -- specifically, whether a malformed (for its purposes) authorization header will trigger an exception or be allowed to pass.
I think there's a reasonable case for calling this behavior "broken," but at the same time I suspect it may be out of the hands of the API Gateway developers, who are working behind an unnamed front-end component that is common to multiple AWS services. API Gateway is a bit of an exception, in the AWS ecosystem, in that the customer can define how headers are manipulated... so this may very well be simply a platform limitation.
I disagree -- in part, and on a technicality -- with #LorenzodeLara's assertion that API Gateway is not compliant with RFC-7235. There is no requirement that a server respond with WWW-Authenticate: -- from the RFC:
Upon receipt of a request for a protected resource that omits credentials, contains invalid credentials (e.g., a bad password) or partial credentials (e.g., when the authentication scheme requires more than one round trip), an origin server SHOULD send a 401(Unauthorized) response that contains a WWW-Authenticate header field with at least one (possibly new) challenge applicable to the requested resource.
The words SHOULD and RECOMMENDED in RFCs indicate desired behavior for which there may be valid exceptions. They are not mandatory requirements.
It is, on the other hand, fully accurate that API Gateway does not at all support authenticating requests from its perspective with HTTP basic auth... but you are only trying to get it to pass those credentials through to the code running inside, which does appear to work, given that your user agent submits credentials without a challenge... assuming you prevent the front-end system from thwarting you, with the addition of a query string.
That's my analysis, subject to correction by someone with access to more authoritative information. In that light, using basic auth may not be the best plan, since it appears to work somewhat by accident.
I hate to come to that conclusion. Basic auth gets a bad rap, which is not wholly merited when combined with HTTPS -- unlike request signing, it typically "just works," right out of the box, even for a user who doesn't understand the difference between GET and POST, much less how to generate a hex-encoded HMAC digest.

Response code 400 or 403 for POST Restful APIs

I am designing a POST Restful API, where I have a situation that I have to authorize a user based upon one of the element provided in the request body.
For eg.
{
division : "1",
name : "MyName",
address:{
no : 123,
street : "abc",
pincode : 222111
}
....
}
So the user making POST request should be authorized to work on division 1. I cannot authorize the user without getting request body.
Also to validate some of the attributes I have to make heavy DB calls in the DB , for eg, to check the above address has a valid value of pincode.
So My question is how should I return the error codes to the user -
[EDIT]If division is not valid(something that doesnt exist in system) in the request - 400 or 403 ?
If division is provided, but user is not authorized and pincode is invalid - 400 for invalid pincode or 403 ?
What should be the error code if pincode is mandatory attribute and is not provided in the request. Should I first check 403 and then 400 or reverse ?
Basically which error code to proceed the other ?
Also is it okay to do something like :
400 – request is bad, syntactically (division/pincode or other mandatory values not provided)
403 – authorize user
400 – request is bad, data specific validation (heavier operation, requiring to hit DB)
[EDIT] we preferred not to use 422 error code
When in doubt, just take a look at the RFC
400 Bad Request
The request could not be understood by the server due to malformed
syntax. The client SHOULD NOT repeat the request without
modifications.
403 Forbidden
The server understood the request, but is refusing to fulfill it.
Authorization will not help and the request SHOULD NOT be repeated. If
the request method was not HEAD and the server wishes to make public
why the request has not been fulfilled, it SHOULD describe the reason
for the refusal in the entity. If the server does not wish to make
this information available to the client, the status code 404 (Not
Found) can be used instead.
If division is not provided in the request - 400 or 403?
I don't think either apply. The syntax -although it's missing some data- is not malformed.
Also 403 seems incorrect because of reasons mentioned above in the quote: authorization will not help etc.
How about 422 Unprocessable Entity?
422 Unprocessable Entity (WebDAV; RFC 4918)
The request was well-formed but was unable to be followed due to
semantic errors.
That is what I usually use in situations like this.
If division is provided, but user is not authorized and pincode is invalid - 400 for invalid pincode or 403?
Again, I don't think either 400 or 403 make a good case here. Specifically for this situation, 401 exists
401 Unauthorized
Similar to 403 Forbidden, but specifically for use when authentication
is required and has failed or has not yet been provided. The response
must include a WWW-Authenticate header field containing a challenge
applicable to the requested resource. See Basic access authentication
and Digest access authentication.
I think you're in the right track. Assuming that every request is being authenticated via (http authorization header)
Returning 400, on missing data is OK, and furthermore you can add error response body explaining what was the reason for the Client request not being accepted (in this case the missing division).
Returning 403, is OK if the client making the request is not authorized to interact with the resource (in this case the division).
You must validate first if the Client is authorized to interact with the resource, so 403 must be sent first, and if a required field is missing you can treat it as a 400 (with a proper explanation).
In case the Client is not authenticated, the correct response should be 401, but like I said before, 1) and 2) in my response are assuming that the Clients are authenticated against the server.
Hope it helps,
Jose Luis

What status code should I use when session token is invalid?

When creating a web service (RESTful), what status code should I use when session token is invalid?
Currently the one in my company sends me a 404, not found, but I think this is not correct, because the resource exists.
Maybe I should use 401 Unauthorized.
What do you think? What status code do you recommend me to use in this scenario? Thanks.
401 Unauthorized.
Your existing session token doesn't authorize you any more, so you are unauthorized.
Don't forget that a session token is just a short-cut to avoid having to provide credentials for every request.
Sending 404 is incorrect because, as you observe, the resource does exist. You just don't currently have authorization to see it.
NB Don't use 403 Forbidden; the HTTP specification defines it as follows: "The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated." That doesn't apply in this case as authorization WILL help.
Looking through the HttpStatusCode enum, I think Unauthorized is probably the closest to what you're looking for.
Take a look at the list there, and read the descriptions for each one.