Axios OPTIONS instead of POST Request. Express Rest API (CORS) - rest

Im trying to use Axios (and VueJs) to make a Cross Origin POST Request to my Rest Api (running on localhost). Instead of doing a POST request, it actually does a OPTIONS request to my Rest Api. This circumvents a middleware function that checks for a token and return 403.
This is the login function
router.post('/login', (req, res) => {
User.authUser(req.body, (err, user) => {
var passwordIsValid = bcrypt.compareSync(req.body.password, user.password);
if (err) throw err;
if (!user) {
res.json({ success: false, message: 'User nicht gefunden' });
} else if (user) {
if (!passwordIsValid) {
res.json({ success: false, message: 'Falsches Passwort' });
} else {
const payload = {
admin: user.admin
};
var token = jwt.sign(payload, config.secret, {
expiresIn: 86400
});
res.json({success: true, message: 'Token!', token: token});
}
}
})
});
How can I get Axios to make a proper POST request? I tried this hack, because I first thought the OPTIONS Request was just a preflight, but there is no request after I return 200 (or 204)
CORS Middleware:
app.use(function(req, res, next) { //set Response Headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
if ('OPTIONS' == req.method) {
res.send(204);
}
else {
next();
}
});

Axios will sometimes send an OPTIONS request as part of a cors preflight if it doesn't know the Content-Type of a request.
You can get explicitly specify the Content-Type when you build the request, and then it should send your POST request as expected.
Instead of
axios.post(url, params), try:
axios.post(url, params, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})

Related

Axios interceptor not working anymore in last version (1.1.3)

I recently upgraded axios in one of my project (from 0.27 to 1.1.3) and the interceptor I created to refresh the user's access token doesn't work anymore, u can find in the screenshot bellow the error I'm having. I searched online but can't find anything working.
To precise, whenever the user's access token expires, my back end send the 401 error and so the interceptor is called. The returned token is good as well as the setting to the headers.
Thank you in advance for your time.
import axios from "axios";
import router from "#/router";
import store from "#/store/index";
const instance = axios.create({
baseURL: "http://localhost:3000",
});
instance.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
const originalRequest = error.config;
console.log("error:", error);
if (
error.config.url != "users/refreshToken" &&
error.response.status === 401 &&
!originalRequest._retry
) {
originalRequest._retry = true;
await instance
.get("users/refreshToken", { withCredentials: true })
.then((response) => {
const token = response.data.accessToken;
console.log("token:", token);
store.state.token = token;
instance.defaults.headers.common["authorization"] = `Bearer ${token}`;
originalRequest.headers["authorization"] = `Bearer ${token}`;
localStorage.setItem("token", token);
})
.catch(() => {
store.commit("logout");
localStorage.removeItem("token");
router.push({ name: "login", params: { error: "refreshToken" } });
});
return instance(originalRequest);
}
return Promise.reject(error);
}
);
export default instance;
The error :

Axios bad request 400 Spotify post

I am getting a bad request of 400 from Axios for trying to get the token from the Spotify API. Can someone please look at my code?. I would really appreciate someone's help.
app.get("/auth/callback", async (req, res) => {
try{
let code = req.query.code || null;
let state = req.query.state || null;
let data = qs.stringify({
grant_type: "authorization_code",
code: code,
redirect_uri: redirect_uri,
});
const response = await axios.post('https://accounts.spotify.com/api/token', data,
{
headers: {
'Authorization': `Basic ${Buffer.from(client_id + ':' + client_secret).toString('base64')}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
})
res.send(response)
}catch(error){
res.send(error)
}
})

axios interceptors how to use them with axios.create()

I have the following code which I import and use in a VueJS application.
I want to be able to errors returned by the API centrally and it seems that interceptors would do the job for me but I don't understand where I set them up
import axios from 'axios'
import store from './store/index'
export default () => {
try{
var token = store.state.user.token.token
}catch(err){
var token = ""
}
return axios.create({
baseURL: "http://localhost:3333/api/v1",
headers: {
"Authorization": `Bearer ${token}`
}
})
}
I have tried this, but it does not work.
import axios from 'axios'
import store from './store/index'
axios.interceptors.request.use((config) => {
console.info("debug ", config);
return config;
}, (error) => {
console.error("debug ", error);
return Promise.reject(error);
});
export default () => {
try{
var token = store.state.user.token.token
}catch(err){
var token = ""
}
return axios.create({
baseURL: "http://localhost:3333/api/v1",
headers: {
"Authorization": `Bearer ${token}`
}
})
}
After some fiddling, I have worked it out.
You have to first create an axios object with axios.create(), then assign your intercepters to the object after which you can return the object. Here is the code I used that worked.
var axiosInstance = axios.create({
baseURL: "http://localhost:3333/api/v1",
headers: {
"Authorization": `Bearer ${token}`
},
})
//This allows you to intercept the request before it is sent and alter headers or anyting else that is passed to the axios config.
axiosInstance.interceptors.request.use((config)=>{
return config
}, (error) => {
console.log("Interceptor Request Error" + error)
})
//This allows you to intercept the response and check the status and error messages and if ncessary reject the promise.
axiosInstance.interceptors.response.use((response) => {
console.log(response.data)
return response
}, (error) => {
console.log("Interceptor Response Error" + error)
})
return axiosInstance
Now I know how to do this, I could move my Authorization code out of the create function and put it in the request interceptor axiosInstance.interceptors.request.use

node.js / axios AUTHENTICATION_FAILURE with PayPal Subscriptions API

I'm using Axios to activate a PayPal subscription since the NODE SDK doesn't support the subscription activation. For doing so I've created this method that generate a PayPal access token:
let getAccessToken = async () => {
return await axios(options).then((response) => {
return response.data.access_token
});
}
the options contains the following details:
const options = {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Access-Control-Allow-Credentials': true
},
data: qs.stringify(data),
auth: {
username: PAYPAL_CLIENT_ID,
password: PAYPAL_CLIENT_SECRET
},
url: 'https://api.sandbox.paypal.com/v1/oauth2/token'
}
this working fine but I'm having some problems activating the subscription, this is the method that handle this:
let activateSubscription = async (accessToken, subscriptionId) => {
return await axios.post(
`${baseURL}/v1/billing/subscriptions/${subscriptionId}/activate`,
{
headers: {
"Authorization": `Bearer ${accessToken}`,
"Content-Type": 'application/json'
}
}).then((data) => {
return true;
})
.catch((error) => {
console.log(error.response.data);
return false;
});
}
Essentially I pass the generated accessToken and the subscriptionId, but I get as response this:
{
name: 'AUTHENTICATION_FAILURE',
message: 'Authentication failed due to invalid authentication credentials or a missing Authorization header.',
links: [
{
href: 'https://developer.paypal.com/docs/api/overview/#error',
rel: 'information_link'
}
]
}
My suspicion was that the generated token was incorrect, so I tried it in postman sending this request:
{{host}}/v1/billing/subscriptions/I-7D10FGKVNMD0/activate
and the returned content is 204 which is okay according to what doc says here.
The request seems correct, what am I doing wrong?
You're setting the headers wrong. From the pastebin:
data: '{"headers":{"Authorization":"Bearer A21AAEj_0lJjny7Hc1aL7l5irIxOqOjyW_pSfT2WC9APAQFXHTYzKL0womW1mZvS6mKWsWMytMc6H6NIMPMnOK7zhzHKHsSAw","Content-Type":"application/json"}}',
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json;charset=utf-8',
'User-Agent': 'axios/0.19.2',
'Content-Length': 170
},
So, PayPal isn't actually getting your Authorization header

Error 405 using axios post request in react native

I'm making an post request using axios in my expo react native app but I don't know why my post request is returning error
Request failed with status code 405
When I check my API on postman so it shows me the expected result. I attached the method which hits onPress on button. Kindly check and provide me a solution.
async onSubmit(ref) {
if (ref.state.emailID && ref.state.password) {
this.showLoader();
await axios.post('http://apiurl.com/api/user/Userlogin?emailID=' + ref.state.emailID + '&password=' + ref.state.password,
{ emailID: ref.state.emailID, password: ref.state.password },
{ headers: { 'Content-Type': 'application/json' } })
.then((response) => {
console.log('Innnn');
this.hideLoader();
console.log("response data: ", response.data);
}).catch(err => {
this.hideLoader();
console.log("error: ", err.message);
})
}
}
Okay, so there are multiple things which are wrong in you code.
To answer your question at start, I would suggest you to add withCredentials: true}
Try adding {withCredentials: true} in your axios request.
Second, with async and await, you don't need to use .then and catch (rather use try..catch)
async onSubmit(ref) {
if (ref.state.emailID && ref.state.password) {
try {
this.showLoader();
const networkReq = await axios.post('http://apiurl.com/api/user/Userlogin?emailID=' + ref.state.emailID + '&password=' + ref.state.password,
{withCredentials: true},
{ emailID: ref.state.emailID, password: ref.state.password },
{ headers: { 'Content-Type': 'application/json' } })
this.hideLoader();
console.log(networkReq.data)
} catch (error) {
this.hideLoader();
console.log("error: ", err.message);
}
}
}
I was doing a very silly mistake, the request has been changed from post to get.