flex-plugin-builder
flex-plugin-builder copied to clipboard
[Bug]: Twilio Functions CORS error
Summary
Twilio Function Blocked by CORS policy
Detailed Description
Hi,
I have created flex plugin to send SMS through a twilio function and deployed it, its working fine with my twilio test account
but when i am doing same functionality with my production account i i am getting the below issue
Access to fetch at 'https://linen-prawn-3862.twil.io/create-new-sms' from origin 'https://flex.twilio.com' has been blocked by CORS policy: 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.
bundle.js:2 POST https://linen-prawn-3862.twil.io/create-new-sms net::ERR_FAILED
startSMS @ bundle.js:2
onClick @ bundle.js:2
u @ twilio-flex.min.js:1519
h @ twilio-flex.min.js:1519
(anonymous) @ twilio-flex.min.js:1519
E @ twilio-flex.min.js:1519
A @ twilio-flex.min.js:1519
M @ twilio-flex.min.js:1519
O @ twilio-flex.min.js:1519
R @ twilio-flex.min.js:1519
Cn @ twilio-flex.min.js:1519
ma @ twilio-flex.min.js:1519
Ue @ twilio-flex.min.js:1519
An @ twilio-flex.min.js:1519
va @ twilio-flex.min.js:1519
Pn @ twilio-flex.min.js:1519
/agent-desktop/WR399…ad9e890b1e5a6a009:1 Uncaught (in promise) TypeError: Failed to fetch
Below is the code of my function
const axios = require('axios');
exports.handler = async function (context, event, callback) {
console.log('----in function----');
const response = new Twilio.Response();
response.appendHeader('Access-Control-Allow-Origin', '*');
response.appendHeader('Access-Control-Allow-Methods', 'POST GET PUT OPTIONS');
response.appendHeader('Content-Type', 'application/json');
response.appendHeader('Access-Control-Allow-Headers', 'Content-Type');
const authed = await validateToken(event.Token, context.ACCOUNT_SID, context.AUTH_TOKEN);
if (typeof authed !== 'object' || !authed.data || authed.data.valid !== true) {
console.log('couldn\'t auth', event.Token);
return callback(null, response);
}
console.log('successfully authed', authed.data)
const client = context.getTwilioClient();
const to = sanitizeNumber(event.To);
const from = sanitizeNumber(event.From);
const channelArgs = {
FlexFlowSid: context.FLEX_FLOW_SID,
Identity: event.To,
Target: event.To,
ChatUserFriendlyName: event.ToFriendlyName || event.To,
ChatFriendlyName: event.ChatFriendlyName || `${event.To} chat`,
PreEngagementData: JSON.stringify({ targetWorker: authed.data.identity })
};
const channelResponse = await createChannel(channelArgs, context.ACCOUNT_SID, context.AUTH_TOKEN);
client.messages.create({
body: event.Message,
to: to,
from: from
}).then(() => {
console.log('adding message to', channelResponse.data.sid);
client.chat.services(context.CHAT_SERVICE_SID)
.channels(channelResponse.data.sid)
.messages
.create({
body: event.Message,
from: from
}).then(() => callback(null, response));
}).catch(err => {
console.error(err);
callback(err);
});
}
Log output
No response
Version of @twilio/flex-ui
1
Version of flex-plugin-scripts
4.5.0
Version of @twilio-labs/plugin-flex
4.0.0
Version of node
14.17.0
Version of npm
7.14.0
OS
Window
Content of package.json
{
"name": "plugin-sms",
"version": "7.0.0",
"private": true,
"scripts": {
"postinstall": "flex-plugin pre-script-check",
"start": "flex-plugin start"
},
"dependencies": {
"@emotion/react": "^11.1.5",
"flex-plugin-scripts": "^4.5.0-beta.0",
"react": "16.5.2",
"react-dom": "16.5.2"
},
"devDependencies": {
"@twilio/flex-ui": "^1",
"react-test-renderer": "16.5.2"
}
}
@oarvindjha you are using https://github.com/twilio/twilio-flex-token-validator I presume? First off, you can simply your code a bit by using the functionValidator
instead of tokenValidator
:
const TokenValidator = require('twilio-flex-token-validator').functionValidator;
exports.handler = TokenValidator(function(context, event, callback) {
// Your normal Twilio Function goes here.
// This block will only be called if your token is validated, otherwise it returns a 403.
});
This would get rid of your
const authed = await validateToken(event.Token, context.ACCOUNT_SID, context.AUTH_TOKEN);
if (typeof authed !== 'object' || !authed.data || authed.data.valid !== true) {
console.log('couldn\'t auth', event.Token);
return callback(null, response);
}
Secondly, can you change response.appendHeader('Access-Control-Allow-Methods', 'POST GET PUT OPTIONS');
to response.appendHeader('Access-Control-Allow-Methods', 'POST, GET, PUT, OPTIONS');
(i.e. with ,
separating out the methods).
More information is available on https://www.twilio.com/docs/flex/developer/plugins/call-functions
@ktalebian I'm also having this issue with a new instance of a flex workspace and a new instance of a twilio plugin and still getting the issue.
I even tried calling locals and deployed servers that has access control allowed for all origin and the issue still persists.
Edit:
Just noticed this:
Using that content type fixed the issue.
Ah, good catch. Sorry I didn't notice that before. Can we close this issue then @rapito?
I didnt open the ticket but I strongly believe that documentation needs to address this more aggressively at the very least.
Maybe flex should throw out warning logs to both browser and terminal if fetch is being used without proper content type.
I understand this is already on the document you listed but I have only read official docs for 3 days straight and Im seeing this just now.
Flex + taskrouter docs are simply huge. 😭
Also, If I search for CORS errors anywhere on twilio github or docs, I should be able to find the above caveat. But that's not the case. if anything, you go down a deeper rabbit hole that misleads you even further.
@rapito I'll bring this up with our Doc team. I'm also going to investigate maybe we should add a fetch
helper method to the flex-plugin
repo to make it easier for you to send requests to Twilio Functions.
I think this is back. I'm now getting this error when I'm trying to execute a method from a twilio function from the flex instance.
Access to fetch at 'https://myfunction.twil.io/foo' from origin 'https://flex.twilio.com' has been blocked by CORS policy: 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.
even while using the same headers, it just started failing out of nowhere:
This is the code on the client:
url = 'https://myfunction.twil.io/foo';
fetch(url, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
method: 'POST',
body: JSON.stringify(body),
}).then(() => {
// do something
}).catch(async (e) => {
// do something else
});
This is the function code that also accepts the headers already and has cors enabled:
const response = new Twilio.Response();
response.appendHeader('Access-Control-Allow-Origin', '*');
response.appendHeader('Access-Control-Allow-Methods', 'OPTIONS, POST, GET');
response.appendHeader('Access-Control-Allow-Headers', 'Content-Type');
// witchcraft
callback(null, response);
@rapito your fetch
call is misconfigured. You can either do
-
'Content-Type': 'application/x-www-form-urlencoded',
withbody: new URLSearchParams(body)
OR
-
'Content-Type': 'application/json',
withbody: JSON.stringify(body)
If you mix and match those, it will not work.
localhost CORS error using GET and POST methods with Access-Control-Allow-Origin set to either "*" or "http://localhost:3000" Using fetch or axios, result is the same.

Seems like the preflight may be interrupting this which is why we end up with "err_failed 200"
Very few if any issues when calling this function from insomnia.
localhost CORS error using GET and POST methods with Access-Control-Allow-Origin set to either "*" or "http://localhost:3000" Using fetch or axios, result is the same.
![]()
Seems like the preflight may be interrupting this which is why we end up with "err_failed 200"
Very few if any issues when calling this function from insomnia.
![]()
@JackCrish, were you able to solve this bug? I'm having the same problem... :/
I having the same problem. Nothing fix it.
I've solved the problem with this:
Serverles service:
const response = new Twilio.Response(); //eslint-disable-line no-undef
response.appendHeader("Access-Control-Allow-Origin", "*");
response.appendHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
response.appendHeader("Access-Control-Allow-Headers", "Content-Type");
response.appendHeader("Content-Type", "application/json");
front-end request using axios as http client:
const response = await this.httpClient.request({
url: "your-url-service",
method: "post",
body: JSON.stringify({ body }),
headers: { "Content-Type": "application/json" },
});
I've solved the problem with this:
Serverles service:
const response = new Twilio.Response(); //eslint-disable-line no-undef response.appendHeader("Access-Control-Allow-Origin", "*"); response.appendHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); response.appendHeader("Access-Control-Allow-Headers", "Content-Type"); response.appendHeader("Content-Type", "application/json");
front-end request using axios as http client:
const response = await this.httpClient.request({ url: "your-url-service", method: "post", body: JSON.stringify({ body }), headers: { "Content-Type": "application/json" }, });
So, did you set axios on httpClient from constructor?
I've solved the problem with this: Serverles service:
const response = new Twilio.Response(); //eslint-disable-line no-undef response.appendHeader("Access-Control-Allow-Origin", "*"); response.appendHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); response.appendHeader("Access-Control-Allow-Headers", "Content-Type"); response.appendHeader("Content-Type", "application/json");
front-end request using axios as http client:
const response = await this.httpClient.request({ url: "your-url-service", method: "post", body: JSON.stringify({ body }), headers: { "Content-Type": "application/json" }, });
So, did you set axios on httpClient from constructor?
yeap, exactly!
Hi,
This is a long open item more than a year now, hence closing it. Feel free to reopen it if still required.