Axios interceptor not working anymore in last version (1.1.3) - axios

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 :

Related

Facing error while requesting the signup request

who I'm and what I'm trying to do :
I am a beginner following and building a MERN stack project tutorial on youtube
I want to make two requests to the server :
the first request is a register/ signUp request (not working fine).
the second request is a login request (working fine).
errors in my console
POST http://localhost:5000/auth/register 500 (Internal Server Error)
AxiosError {message: 'Request failed with status code 500', name: 'AxiosError', code: 'ERR_BAD_RESPONSE', config: {…}, request: XMLHttpRequest, …}
my console looks like this
source code:
Auth.jsx
const handleSubmit = (e) => {
// setConfirmPass(true);
e.preventDefault();
if (isSignUp) {
data.password === data.confirmpass
? dispatch(signUp(data))
: setConfirmPass(false);
} else {
dispatch(logIn(data));
}
};
AuthRequest.js
import axios from "axios";
const API = axios.create({ baseURL: "http://localhost:5000" });
export const logIn = (formdata) => API.post("/auth/login", formdata);
export const signUp = (formdata) => API.post("/auth/register", formdata);
AuthAction.js
import * as AuthAPI from "../api/AuthRequest.js";
export const logIn = (formData) => async (dispatch) => {
dispatch({ type: "AUTH_START" });
try {
const { data } = await AuthAPI.logIn(formData);
dispatch({ type: "AUTH_SUCCESS", data: data });
} catch (error) {
console.log(error);
dispatch({ type: "AUTH_FAIL" });
}
};
export const signUp = (formData) => async (dispatch) => {
dispatch({ type: "AUTH_START" });
try {
const { data } = await AuthAPI.signUp(formData);
dispatch({ type: "AUTH_SUCCESS", data: data });
} catch (error) {
console.log(error);
dispatch({ type: "AUTH_FAIL" });
}
};
Can somebody tell me why my sighUp request is showing me an error and login is working fine. How to fix that errors.
both request are working fine using thunderclient.
Sorry If I am not able to understand properly here what my problem is. you can open the youtube video link (at time 45:44). this is what I'm trying to do. I have added the cors package also but for the sighup request it is not working.

Router API cannot use res.end() or res.json() in catch/

I dont know why but if function not get error, it work perfectly , but when it get error, catch always display
res.end is not a function
it like i can't use res in catch, but in try res still work, Am i missing something?
import axios from "axios";
import { NextApiResponse } from "next";
const handler = async (res: NextApiResponse): Promise<void> => {
return new Promise((resolve, _) => {
axios({
method: "get",
headers: { "Content-type": "application/json" },
url:
process.env.NODE_ENV === "production"
? "https://.../refresh_token"
: "http://localhost:4000/refresh_token",
withCredentials: true,
})
.then((response) => {
res.statusCode = 200;
res.setHeader("Content-Type", "application/json");
res.setHeader("Cache-Control", "max-age=180000");
res.end(JSON.stringify(response.data));
resolve();
})
.catch((error) => {
res.statusCode = 500;
res.end(JSON.stringify((error as Error).message));
resolve();
});
});
};
export default handler;
The first parameter in your handler function should be a NextApiRequest object, not a NextApiResponse object:
const handler = async (req: NextApiRequest, res: NextApiResponse): Promise<void> => { //...
Since req is expected to be the first parameter, passing res there will mean calling end on the NextApiRequest object — an error because end doesn't exist there.

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

How can I do refresh auth token logiс with axios for multiple requests?

I was trying to do it like this, but for three requests it sends three refresh requests:
1, 2, 3 fails with 401
refresh success, 1 success, 2, 3 fails
refresh success, 2 success, 3 fails
refresh success 3 success
I can't put that much load on a mobile device (even if there was only 3 refresh without "refail")
Here is my code:
function requestRefreshToken(refreshToken, accessToken) {
return axios
.create({
baseURL: apiUrl + Endpoints.AUTH.REFRESH,
skipAuthRefresh: true,
headers: {
'Accept-Language': 'ru',
'User-Agent': `${Platform.OS} ${packageJson.version}`,
Authorization: accessToken,
},
})
.post(
'',
{
grant_type: GrantTypes.REFRESH_TOKEN,
refresh_token: refreshToken,
client_id: Client.id,
client_secret: Client.secret,
},
{ validateStatus },
);
}
const refreshAuthLogic = async failedRequest =>
Keychain.getCredentials()
.then(old => requestRefreshToken(old.refreshToken, old.accessToken))
.then(({ data: credentials }) => {
failedRequest.config.headers.Authorization = `${credentials.token_type} ${
credentials.access_token
}`;
return Keychain.setCredentials(credentials);
});
createAuthRefreshInterceptor(axios, refreshAuthLogic, {
retryInstance: axios,
skipWhileRefreshing: true,
onRetry: function(config) {
return Keychain.getCredentials().then(({ accessToken }) =>
axios({
...config,
header: { ...config.headers, Authorization: accessToken },
}),
);
},
});
axios.interceptors.response.use(
r => r,
request => {
if (request.response.status === 401) {
return Keychain.getCredentials().then(({ accessToken }) =>
axios({
...request.config,
header: { ...request.config.headers, Authorization: accessToken },
}),
);
}
},
);
Solved with this! Seems there is no way solving it without failed request queue( https://gist.github.com/mkjiau/650013a99c341c9f23ca00ccb213db1c
Here's a quick way I implemented it.
I found it a bit simpler to reason about the code.
I've adapted it from this solution:
HERE
let refreshTokenPromise: null | Promise < any > ;
instance.interceptors.response.use(r => {
const {
data
} = r;
if (data.errors && data.errors[0].message === "AUTH_EXPIRED") {
if (!refreshTokenPromise) {
refreshTokenPromise = fetchRefreshToken().then(data => {
refreshTokenPromise = null;
return data;
});
}
return refreshTokenPromise.then(token => {
if (r.config.headers) r.config.headers["Authorization"] = token;
return instance.request(r.config);
});
}
return r;
});

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

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' }
})