We have a simple application structure that our ReactJs front-end make request to api gateway which does a proxy-integration with a lambda function. Since our api gateway is passing requests as they are without any modification and do the same when returning responses to customer so the place we are going to add http security headers would be in the lambda function itself. I have done some research on how it can be achived but all the answers I got searching in Google mention lambda#Edge+Cloudfront similar to this post which we do not use at all, does it mean we have to change our structure by adding these two things? Thanks.
The article you reference assumes the backend is static (e.g. S3) and cannot set headers. That's why Lambda#Edge is used.
It sounds like your current setup should work without any changes... Did you try adding headers in the code?
I have this code working perfectly for the APIGW + Lambda (proxy integration) combo.
exports.handler = async function (event) {
var response = {
statusCode: 200,
headers: {
'Content-Type': 'application/json; charset=utf-8',
'X-My-Header': 'whatever'
},
body: JSON.stringify({status: 'OK'}),
}
return response
}
Add HSTS header in AWS Lambda.
Related
I've got an API gateway v2 which is using a proxy integration to lambda.
I'm trying to pass a custom header value via a GET call to my API.
...
fetch(new Request(refreshUrl, {
method: 'GET',
headers: new Headers({
'refreshToken': user?.tokens.refreshToken
})
}))
...
I can't for the life of me figure out how to get APIGW to pass that header value to my lambda. When I log the event received in my lambda, my "refreshToken" header is nowhere to be seen.
I've tried to add parameter mapping such as the following to my lambda integration in apigw with no success:
$request.header.refreshtoken
And the documentation for such scenarios with AWS only seems to show for APIGW v1.
Solved:
The issue wasn't related to APIGW. The request parameter mapping is correct.
The problem was that I was proxying the api via cloud front and I needed to whitelist the header in my distribution.
I am trying to set up an API Gateway to call another lambda function that will upload an image to S3. The feature works well when I am using an app like POSTMAN, however when I run the browser using React I am getting the following error.
Access to fetch at 'https://.../upload' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
In my API Gateway I have the following configuration for that method
Gateway Responses for UserUpload API: default 4XX (not checked), default 5XX (not checked)
Methods: post (checked), options (checked)
Access-Control-Allow-Methods: options, post
Access-Control-Allow-Headers: '*'
Access-Control-Allow-Origin: '*'
This API uses an authorizer, I am using the one provided by Auth0 and have not edited the code at all.
And the function that my authorizer calls returns the response like the below (eg happy path):
exports.handler = async (event) => {
//do data checks and upload to s3
return {
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Origin": "*",
},
statusCode: 200,
body: JSON.stringify({ message: "success" }),
};
This is my first time setting up both a lambda function, authorisation provider and API Gateway so I might be missing something obvious. I have also tried added mode: no-cors to my fetch POST requests however they still fail in a very similar way.
From what I can tell by looking at the logs of the authorizer and the lambda function that uploads the images, is that they are not even being called. So it appears the CORS error is with the API Gateway.
I have seen in a few tutorials that in their aws template yaml files they add an option AddDefaultAuthorizerToCorsPreflight as False. I can't see this anywhere in the API Gateway console.
Update: I have tested my function with the custom authoriser turned off and it works. So I know that CORS works for the options method, and for the returned request on the lambda function. It is the custom authoriser that is the problem.
The flow is currently:
Method Request - Auth: my-auth-0-authorizer
Integration Request - Type: Lambda_proxy
Lambda function
Integration response - [greyed out Proxy integrations cannot be configured to transform responses]
Method Response: HTTP Status: Proxy (with Access-Control-Allow-Origin in the response headers)
What do I have to do differently or change to allow my authoriser to respect the CORS config?
Update: After leaving my API Gateway for a day, successful responses are now working (using the flow mentioned above). I am not sure if there was a glitch in the system or there was unexpected occurring but it is now working. I am still getting a CORS issue but now only with bad responses.
The custom authoriser fails by return context.fail("Unauthorized"); and when this occurs my browser gets a CORS error. Do I have to set up special gateway responses for 4XX responses?
I have a use case where when a user hits my API gateway I spawn a Lambda. The Lambda is using aws serverless express.
The Lambda has the responsibility to fetch the data from a url. Lets say this url is tiny url which is amazons url.
I am fetching the data. My code to fetch the data is
function (req, res) {
var request1 = require('request')
res.setHeader('Content-Type', 'text/html; charset=utf-8');
request1.get('http://a.co/d/dBpaoQo')
.on('response', response => {
response.pipe(res);
});
}
However, when I see the data at the client end, I see the data as
��P_k�0}ϧH}� U�e輹{X�`����
���1�\��bbmQ��]���p����CZ/��^w�q�F�����C�Ν�gy���I�����!�h�<T��s0�W����r��ko7���j�ȓ�ΊyF<��<��z�hp+�L�&�s%:|
F�l/f٫.��*���z�2����0���JGD��8A��W��1�=�S��3����˜m.�Do~�|s{����O�����G���-2;O�h�;^�����4�$�D?&���F֊�w����Џ~�\�P��0,Z�7´�Z
��s��g�\��c��ڿ�N�M���>�^�,Ka?��,�'nd�H�Z]�����\���#s��2������#�
ra#N<��V�
(Not Pasting the whole content).
If I run the server locally it shows the data in correct format. It is basically API gateway which is messing up with the data. I even applied
res.setHeader('Content-Type', 'text/html; charset=utf-8')
in my code as suggested on stackoverflowlink
Can anyone point me what am I doing wrong.
Ok this was an issue with Lambda and not with using API-Gateway. When I was fetching the data it was a compressed file.
I had to put in request headers(request where I am requesting the URL to give me data)
Accept-Encoding: 'none'
However, I did not understand why it is working locally and not on Lambda. When I run the same code locally I get the correct file.
I have a AWS Lambda function that is triggered via AWS API Gateway. When I test my function on Lambda it is working. When I send a POST request to the API url via ajax, I get a 502 bad gateway error.
XMLHttpRequest cannot load https://xxxxxxxx.execute-api.us-east-1.amazonaws.com/prod/myLambdaFunction. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'mywebsite.com' is therefore not allowed access. The response had HTTP status code 502.
Obviously this was a CORS issue, so I thought I could change the CORS settings in my AWS API Gateway URL which I did, but I am still getting an error for this.
What do I have to change on AWS side or my own to be able to POST to the URL?
Unfortunately there is a known issue with many classes of 4xx and 5xx errors where CORS headers will not be sent, even if you've added CORS support via the console.
As noted in comments, the CORS error is a side effect of the fact that your API is returning a 502. This often occurs if you are using the LAMBDA_PROXY integration type and are returning invalid JSON from your Lambda function.
Please try either using the test invoke functionality from the console or enable logging in your API to debug further.
I solved that exact same problem by outputting the CORS header myself.
See below - and I hope that'll help.
Teebo
Amazon docs
function respond(context, responseData) {
var response = {
statusCode: 200,
body: JSON.stringify(responseData),
headers: {
"Content-Type": "application/json; charset=utf-8",
"Access-Control-Allow-Origin": "*"
}
};
context.succeed(response); }
I have a WebApi secured with Basic Auth which is applied to the entire Api using a AuthorizationFilterAttribute. I also have SignalR Hubs sitting on several of my Api Controllers.
Alongside this I have a web page which makes use of my WebApi. The web page is mostly written in Backbone, so in order to make calls to my secured WebApi, I have added the following jquery
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
jqXHR.setRequestHeader('Authorization', 'Basic ' + Token);
return true;
}
});
This works for communicating with my Api Controllers, but adding the above code has broken the connection to my SignalR Hubs, specifically:
XMLHttpRequest cannot load http://localhost:50000/signalr/negotiate?_=1366795855194.
Request header field Authorization is not allowed by Access-Control-Allow-Headers.
Removing the jqXHR.setRequestHeader() line restores my SignalR Hub connection but breaks the Api calls.
Given the above, I could do something hacky and only set the request header if the request being made isn't to /signalr but that just feels dirty...
Is there a cleaner way around this?
Am I just doing something silly? Has anyone else ran in to this?
What I didn't mention before is that I have a DelegatingHandler which sends back the correct Headers to any request coming in to my WebApi. This works perfectly for any requests to my WebApi but I wrongly assumed that this would also apply to SignalR requests.
As SignalR relies on several different transport methods, it doesn't seem reasonable to assume I have access to Authorization headers in the first place - they're not a requirement of all WebSockets implementations for example (see here)
My current solution has been to make use SignalR's HubPipeline (detailed here). Using this, I believe I can pass the Basic Auth credentials in a query string and write a separate module for handling Authorization for the SignalR requests:
Passing the Query string
$.connection.hub.qs = "auth=" + MyBase64EncodedAuthString;
The Filter
public class SignalrBasicAuthFilterAttribute: Attribute, IAuthorizeHubConnection {
public bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request) {
var authString = request.QueryString["auth"];
// ... parse, authorize, etc ...
return true;
}
}
Registering the Filter
var globalAuthorizer = new SignalrBasicAuthFilterAttribute();
GlobalHost.HubPipeline.AddModule(new AuthorizeModule(globalAuthorizer, globalAuthorizer));
Additionally...
Note that because it's not a reliable assumption to send an Authorization header with SignalR requests, for the aforementioned reasons, I am still filtering my $.ajaxSetup to only affect non-SignalR requests:
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
if (settings.url.indexOf("/signalr") == -1)
jqXHR.setRequestHeader('Authorization', 'Basic ' + Token);
return true;
}
});
In doing this, I'm leaving SignalrBasicAuthFilterAttribute class to take on full responsibility for Authorizing SignalR requests.
Further Reading:
http://weblogs.asp.net/davidfowler/archive/2012/11/11/microsoft-asp-net-signalr.aspx
http://eworldproblems.mbaynton.com/2012/12/signalr-hub-authorization/
SignalR authentication within a Controller?
I think the real solution for the issue will be to make sure that "Authorization" is part of the allowed Headers(Access-Control-Allow-Headers) returned from the signalR response for "negotiate" request.
You could register the header in your web.config just like this possibility.
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Headers" value="Authorization" />
</customHeaders>
</httpProtocol>