Express CORS response - express

I am using express to return an api response retrieved via a request call.
router.post('/', function(req, res){
var options = {
...
}
rp(options)
.then(function (parsedBody) {
console.log(parsedBody);
res.json(parsedBody)
})
The console log displays the expected payload, also when I use Postman I also see the expected payload.
When though my client app gets the response it is:
Response {type: "cors", url: "http://localhost:3001/api/", redirected: false, status: 200, ok: true, …}
Ive tried adding CORS middleware:
app.use(function(request, response, next) {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers",
"Origin, X-Rquested-With, Content-Type, Accept");
next();
});
My client is a very simple react app using fetch:
fetch('http://localhost:3001/api/', {
method: 'POST',
dataType: 'JSON',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: data,
}).then((response) => {
console.log(response);
}).catch((response) => {
console.log('Error');
});
My react app is localhost:3000 and the express api localhost:3001, the expected payload is a very simple object...
{
athlete: {
firstname: "Matt"
...
}
}
How can I just forward on the api request response to the clients fetch success method?

The problem is not CORS related, the response within the react app needed parsing as json:
.then((response) => {
console.log(response.json());
})

Related

Spotify returning 200 on token endpoint, but response data is encoded

I'm working through this tutorial on creating an app that uses the Spotify API. Everything was going great until I got to the callback portion of authenticating using the authentication code flow.
(I do have my callback URL registered in my Spotify app.)
As far as I can tell, my code matches the callback route that this tutorial and others use. Significantly, the http library is axios. Here's the callback method:
app.get("/callback", (req, res) => {
const code = req.query.code || null;
const usp = new URLSearchParams({
code: code,
redirect_uri: REDIRECT_URI,
grant_type: "authorization_code",
});
axios({
method: "post",
url: "https://accounts.spotify.com/api/token",
data: usp,
headers: {
"content-type": "application/x-www-form-urlencoded",
Authorization: `Basic ${new Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64")}`,
},
})
.then(response => {
console.log(response.status); // logs 200
console.log(response.data); // logs encoded strings
if (response.status === 200) {
res.send(JSON.stringify(response.data))
} else {
res.send(response);
}
})
.catch((error) => {
res.send(error);
});
Though the response code is 200, here's a sample of what is getting returned in response.data: "\u001f�\b\u0000\u0000\u0000\u0000\u0000\u0000\u0003E�˒�0\u0000Ee�uS\u0015��\u000e�(\b\u0012h\u0005tC%\u0010\u0014T\u001e�����0��^޳:���p\u0014Ѻ\u000e��Is�7�:��\u0015l��ᑰ�g�����\u0"
It looks like it's encoded, but I don't know how (I tried base-64 unencoding) or why it isn't just coming back as regular JSON. This isn't just preventing me logging it to the console - I also can't access the fields I expect there to be in the response body, like access_token. Is there some argument I can pass to axios to say 'this should be json?'
Interestingly, if I use the npm 'request' package instead of axios, and pass the 'json: true' argument to it, I'm getting a valid token that I can print out and view as a regular old string. Below is code that works. But I'd really like to understand why my axios method doesn't.
app.get('/callback', function(req, res) {
// your application requests refresh and access tokens
// after checking the state parameter
const code = req.query.code || null;
const state = req.query.state || null;
const storedState = req.cookies ? req.cookies[stateKey] : null;
res.clearCookie(stateKey);
const authOptions = {
url: 'https://accounts.spotify.com/api/token',
form: {
code: code,
redirect_uri: REDIRECT_URI,
grant_type: 'authorization_code',
},
headers: {
Authorization: `Basic ${new Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64')}`,
},
json: true,
};
request.post(authOptions, function (error, response, body) {
if (!error && response.statusCode === 200) {
const access_token = body.access_token;
const refresh_token = body.refresh_token;
var options = {
url: 'https://api.spotify.com/v1/me',
headers: { Authorization: 'Bearer ' + access_token },
json: true,
};
// use the access token to access the Spotify Web API
request.get(options, function(error, response, body) {
console.log(body);
});
// we can also pass the token to the browser to make requests from there
res.redirect('/#' + querystring.stringify({
access_token: access_token,
refresh_token: refresh_token,
}));
} else {
res.redirect(`/#${querystring.stringify({ error: 'invalid_token' })}`);
}
});
});
You need to add Accept-Encoding with application/json in axios.post header.
The default of it is gzip
headers: {
"content-type": "application/x-www-form-urlencoded",
'Accept-Encoding': 'application/json'
Authorization: `Basic ${new Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64")}`,
}

Cors error - ngrok & express & axios issue when trying to make POST request to the server

I am experiencing an issue when trying to make POST request to the server.
both frontend and backend are ngrok hosting.
this is the POST request:
export async function createTest(test: any) {
try {
const res = await axios.post(
`${backendDomain}/test`,
{id: test, name: 'test'},
{
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
'Access-Control-Allow-Methods': 'POST',
},
}
)
const newTest = res.data
return newTest
} catch (error) {
console.log(error)
}
}
this is the backendDomain: https://sd21-23-221-223-216.ngrok.io
Backend:
const corsOptions = {
origin: "https://dz23-12-256-124-663.eu.ngrok.io",
methods: ['GET', 'PUT', 'POST', 'HEAD', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'Origin', 'Access-Control-Allow-Origin'],
credentials: true,
}
app.use(cors(corsOptions))
Error:
Access to XMLHttpRequest at 'https://sd21-23-221-223-216.ngrok.io/test' from origin 'https://dz23-12-256-124-663.eu.ngrok.io' has been blocked by CORS policy:
Request header field access-control-allow-methods is not allowed by Access-Control-Allow-Headers in preflight response.
More wierd is that I also have GET request which sometimes work and sometimes not.
any ideas?
You need to add this header param ngrok-skip-browser-warning with any value
Example:
$.ajax({
url: 'https://5120-143-202-253-244.eu.ngrok.io/api',
type: 'GET',
headers: {
"ngrok-skip-browser-warning":"any"
},
success: function (data) {
console.log(data);
}
});

How to handler server redirect from axios

I have a vue web app that uses axios to communicate with an API. The authentication is handled by the server, and not by my app. That is, the server ensures that the user cannot see the app before they have authenticated.
Of course, after some time the user's authentication token expires and my app only notices this when it fires off a get/post request to the API. When this happens the axios request returns a redirect to a login page that, when printed to the console, looks something like this:
config: Object { url: "https://...url for my request...",
method: "get", baseURL: "...base url for api", … }
data: "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<HTML>\n<HEAD>\n<TITLE>Need Authentication</TITLE>\n<link rel=\"stylesheet\" href=\"/Steely.css\" type=\"text/css\">\n</HEAD>\n<BODY>....</BODY>\n</HTML>\n"
headers: Object {
connection: "Keep-Alive",
"content-encoding": "gzip", "content-length": "1686", …
}
request: XMLHttpRequest {
readyState: 4, timeout: 0, withCredentials: false, …
}
status: 200
statusText: "OK"
<prototype>: Object { … }
app~d0ae3f07.235327a9.js:1:97292
What is the best way to redirect the user to this login page and then resume my original request? At the moment I am not even succeeding in recognising this. My axios code tries, and fails, to recognise when this happens and then redirect to user a vue component that has a login page. The relevant part of code looks like this:
export default new class MyAPI {
constructor() {
this.axios = axios.create({
headers: {
'Accept': 'application/json',
'Cache-Control': 'no-cache',
'Content-Type': 'application/json',
},
baseURL: `https://.../api`,
});
}
// send a get request to the API
GET(command) {
return new Promise((resolve, reject) => {
this.axios.get(command)
.then((response) => {
if (response && response.status === 200) {
if ( response.data && typeof response.data == 'string' && response.data.includes('Require authentication') ) {
store.dispatch('authenticate', this.baseURL+'/'+command).then( (resp) => resolve(resp.data) )
} else {
resolve(response.data);
}
} else {
reject(response.data);
}
})
.catch((err) => { reject('Internal error'+err); });
});
}
}
This results in the dreaded
Internal errorTypeError: e(...) is undefined
error, although this error is almost certainly triggered further down the code since I not recognising the login authentication request.
Is anyone able to recommend how best to recognise and process the login request?

How to send data to Stripe nodejs express backend

I tried integrating Stripe into my React app using the official doc at https://stripe.com/docs/recipes/elements-react. If you could go through this doc, you'll find out they're using a static value as amount (2000).
// server.js
const app = require("express")();
const stripe = require("stripe")("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
app.use(require("body-parser").text());
app.post("/charge", async (req, res) => {
try {
let {status} = await stripe.charges.create({
amount: 2000,
currency: "usd",
description: "An example charge",
source: req.body
});
res.json({status});
} catch (err) {
res.status(500).end();
}
});
The post API from frontend using fetch is:
async submit(ev) {
let {token} = await this.props.stripe.createToken({name: "Name"});
let response = await fetch("/charge", {
method: "POST",
headers: {"Content-Type": "text/plain"},
body: token.id
});
if (response.ok) console.log("Purchase Complete!")
}
Here, they're sending the token ID and referencing it in the backend as source:req.body.
Now I have tried to send amount from the frontend through the POST request as follows:
body:{
amount: 2000,
tokenId: token.Id
}
and then referencing it in backend as
...
amount: req.body.amount,
source: req.body.tokenid
...
It doesn't work. And consoling both returns undefined
I have tried many things like removing content-type header and pretty little things. Someone pointed out that I should change content-type to application/json and I've thought of setting
app.use(require("body-parser").text()) to app.use(require("body-parser").json()) but decided to consult you guys first.
If I understand you correctly, you want to post a json from client to express server. If so:
Client
fetch({
method: 'POST',
body: JSON.stringify({
amount: 2000,
tokenId: token.Id
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
Server
const app = express();
// if express >= 4
app.use(express.json());
app.post("/charge", async (req, res) => {
console.log(req.body);
});
Any by the way tokenId !== tokenid (in req.body.tokenid)

Is there a limit in the body of a request to an api in React native?Because i cant send large base64 to server

It says me syntax error: JSON Parse error. unrecognized token '<'
Iam using Fetch to do the request.It let me send short base64 strings i tried so what can i do?
This is my call to the api:
export function uploadPost(post) {
let data = {
body: post.body,
picture: post.picture,
type: post.type,
user: {
_id: post.user._id,
name: post.user.name,
picture: post.user.picture
}
}
var headers = {
'Content-Type': 'application/json',
'Access-Control-Origin': '*'
}
return fetch(URL + "/uploadPost", {
method: "post",
headers: headers,
body: JSON.stringify(data)
})
.then(response => Promise.resolve(response.json()))
.catch(err => {
return Promise.reject(err);
})
}
I finally solved it. The problem was that the response was returning a 413 status and I found out that means payload too large. So I added to my node js express server this lines:
var app = express();
//after
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));