I get the following message in the Chrome dev tools console when submitting a contact form (making a POST request) on the /about.html section my portfolio web site:
Access to XMLHttpRequest at 'https://123abc.execute-api.us-east-1.amazonaws.com/prod/contact' from origin 'https://example.net' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'https://example.net/' that is not equal to the supplied origin.
I don't know how to troubleshoot this properly, any help is appreciated.Essentially, this is happening (https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSAllowOriginNotMatchingOrigin) and I don't know where within my AWS assets to fix it. This person had same problem, but i'm unsure of how to apply their fix (CORS header 'Access-Control-Allow-Origin' does not match... but it does‼)
Here is a description of the AWS stack:
Context, I am using an S3 bucket as static website using CloudFront and Route 53, this stuff works fine, has for years. When I added the form, I did the following to allow the HTTP POST request:
Cloudfront, On the site's distribution I added a behavior with all settings default except:
Path pattern: /contact (I am using this bc this is the API Gateway resource path ending)
Origin and origin groups: S3-Website-example.net.s3-website... (Selected correct origin)
Viewer protocol policy: HTTP and HTTPS
Allowed HTTP methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
Cache HTTP methods GET and HEAD methods are cached by default: Checked OPTIONS box
Origin request policy - optional: CORS-S3Origin
Response headers policy - optional: CORS-With-Preflight
API Gateway, Created a REST API with all default settings except:
Created a resource: /contact
Created a method: POST
For /contact, Resource Actions > Enable CORS:
Methods: OPTIONS and POST both checked
Access-Control-Allow-Origin: 'https://example.net' (no ending slash)
Clicked "Enable CORS and Replace existing headers"
Results are all checked green:
✔ Add Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin Method Response Headers to OPTIONS method
✔ Add Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin Integration Response Header Mappings to OPTIONS method
✔ Add Access-Control-Allow-Origin Method Response Header to POST method
✔ Add Access-Control-Allow-Origin Integration Response Header Mapping to POST method
Created a stage called "prod", ensured it had the /contact resource, and deployed.
At the /contact - POST - Method Execution, The test works as expected (triggers Lambda func that uses SES to send email, which I do actually receive).
The only thing I feel unsure about with API Gateway is after I enable the CORS, I can't seem to find a place where that setting has been saved, and if I click again on enable CORS, it is back to the default form ( with Access-Control-Allow-Origin: '')*
Amazon SES, set up 2 verified identities for sending/receiving emails via lamda.
Lamda, set up a basic javascript function with default settings, the REST API is listed as a trigger, and does actually work as previously mentioned. The function code is:
var AWS = require('aws-sdk');
var ses = new AWS.SES({ region: "us-east-1" });
var RECEIVER = 'myemail#email.com';
var SENDER = 'me#example.net';
var response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
"isBase64Encoded": false,
"body": "{ \"result\": \"Success\"\n}"
}
exports.handler = async function (event, context) {
console.log('Received event:', event);
var params = {
Destination: {
ToAddresses: [
RECEIVER
]
},
Message: {
Body: {
Text: {
Data: 'first name: ' + event.fname + 'last name: ' + event.lname + '\nemail: ' + event.email + '\nmessage: ' + event.message,
Charset: 'UTF-8'
}
},
Subject: {
Data: 'Website Query Form: ' + event.name,
Charset: 'UTF-8'
}
},
Source: SENDER
};
return ses.sendEmail(params).promise();
};
The only thing i can think of here is to maybe update the response to have "headers": {"Access-Control-Allow-Origin": "https://example.net"}
S3 bucket that holds the site contents, in permissions > CORS, I have the following JSON to allow a post of the contact form (notice no slash):
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"POST"
],
"AllowedOrigins": [
"https://example.net"
],
"ExposeHeaders": []
}
]
Permissions/Roles, Established Roles and permissions per
AWS guide: create dynamic contact forms for s3 static websites using aws lambda amazon api gateway and amazon ses
video titled: "Webinar: Dynamic Contact Forms for S3 Static Websites Using AWS Lambda, API Gateway & Amazon SES"
Client code, this is a very milk toast function being called to post the form on click.
function submitToAPI(event) {
event.preventDefault();
URL = "https://123abc.execute-api.us-east-1.amazonaws.com/prod/contact";
const namere = /[A-Za-z]{1}[A-Za-z]/;
const emailre = /^([\w-\.]+#([\w-]+\.)+[\w-]{2,6})?$/;
let fname = document.getElementById('first-name-input').value;
let lname = document.getElementById('last-name-input').value;
let email = document.getElementById('email-input').value;
let message = document.getElementById('message-input').value;
console.log(`first name: ${fname}, last name: ${lname}, email: ${email}\nmessage: ${message}`);
if (!namere.test(fname) || !namere.test(lname)) {
alert ("Name can not be less than 2 characters");
return;
}
if (email == "" || !emailre.test(email)) {
alert ("Please enter valid email address");
return;
}
if (message == "") {
alert ("Please enter a message");
return;
}
let data = {
fname : fname,
lname: lname,
email : email,
message : message
};
$.ajax(
{
type: "POST",
url : URL,
dataType: "json",
crossDomain: "true",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(data),
success: function () {
alert("Successful");
document.getElementById("contact-form").reset();
location.reload();
},
error: function () {
alert("Unsuccessful");
}
});
}
The problem was that the response in the lambda function had "Access-Control-Allow-Origin" set to "*".
This should have been set to the exact origin (no trailing slash), so if the origin is 'https://example.net', then the response in the lamda function should have "Access-Control-Allow-Origin" set to 'https://example.net' as shown below:
var response = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "https://example.net"
},
"isBase64Encoded": false,
"body": "{ \"result\": \"Success\"\n}"
}```
I am using Axios to make a POST request with the following headers:
let reqConf = {
headers: {
'x-xsrf-token': '....',
'Content-Type': 'Application/json',
'Access-Control-Request-Headers': 'content-type',
'Access-Control-Allow-Headers': 'Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Allow-Headers, x-xsrf-token'
}
}
I make a post call like so: const response = await axios.post(url, request, reqConf )' I get the following error message: Request blocked by CORS policy: Request Header x-xsrf-token field is not allowed by Access-Control-Allow-Headers`, but if I remove that header from my request I still get the same error but for other headers such as Content-Type.
I have modified the server config to allow Header set Access-Control-Allow-Origin "*". I have set Access-Control-Allow-Headers with all of my headers and my OPTIONS call returns 200 in browser. Is there something else I am missing in my request?
I'm trying to set up an axios post request to add members to an audience list, but I can't figure out how to add the API key (keeps giving error 401: 'Your request did not include an API key.'). I've tried a bunch of things in the "Authorization" header, like what I put below (also: "Bearer ${mailchimpKey}", "${mailchimpKey}", "Bearer ${mailchimpKey}", "Basic ${mailchimpKey}", and probably more...).
I also don't know what the "username" would be, but "any" worked when I tested the API elsewhere.
Does anyone know how I should set this up?
axios
.post(
`https://${server}.api.mailchimp.com/3.0/lists/${list_id}/members`,
{
email_address: email,
status: "subscribed",
},
{
"User-Agent": "Request-Promise",
Connection: "keep-alive",
Authorization: `Basic any:${mailchimpKey}`,
// Testing on localhost
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type",
}
)
If your intention is to use HTTP Basic authentication, just use the Axios auth config option
axios.post(
`https://${server}.api.mailchimp.com/3.0/lists/${encodeURIComponent(list_id)}/members`,
{
email_address: email,
status: "subscribed",
},
{
auth: {
username: "anystring",
password: mailchimpKey
},
headers: { // personally, I wouldn't add any extra headers
"User-agent": "Request-Promise"
}
}
)
HTTP Basic auth headers look like
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
where the string after "Basic" is the Base64 encoded "username:password" string. Axios provides the auth option as a convenience so you don't need to encode the string yourself.
Some other problems you had were:
Adding request headers outside the headers config option
Attempting to send Access-Control-Allow-Origin and Access-Control-Allow-Headers as request headers. These are response headers only. Adding them to your request will most likely cause more CORS errors
I'm developing a Mantis BT client in ColdFusion but I have a problem when I try to make requests from a different domain.
If I making requests from the same domain where I installed Mantis BT all work fine but when I try to make a request from a different domain or the same domain with another port(localhost:8500 - ColdFusion) the browser return "Failed to load https://localhost/mantis/api/rest/users/me: Response for preflight has invalid HTTP status code 401." error.
I have added all headers in mantis config but it still not working.
If I try to make a request with postman all work fine.
var settings = {
"async": true,
"crossDomain": true,
"url": "localhost:8080/mantis/api/rest/users/me",
"method": "GET",
"headers": {
'Access-Control-Expose-Headers': 'Access-Control-Allow-Origin',
'Access-Control-Allow-Origin': '*',
'Authorization': 'MAzzT5UD4cjxwwOayyLFAXnlIPQJmiL_'
}
}
$.ajax(settings).done(function (response) { console.log(response); });
I resolved it by enable headers module in apache.
Trying to request cors request with code:
export default Collection.extend({
model: person,
url () {
return 'http://127.0.0.1:5000/person/'
},
ajaxConfig: function () {
return {
headers: {
'Access-Control-Allow-Origin': 'http//:127.0.0.1:3000'
},
xhrFields: {
withCredentials: false
}
};
},
})
I'm sending request with http//:127.0.0.1:3000 but if use * i still get error below
XMLHttpRequest cannot load http://127.0.0.1:5000/person/. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
How to handle this kind of request?
Rather than your Collection sending the 'Access-Control-Allow-Origin': 'http//:127.0.0.1:3000' in its request headers, your server at http://127.0.0.1:5000 needs to send it in its response headers to the pre-flight request.
If you can give some details about the server setup, I can help you to figure out how to add the header to the response.