For each request to the backend, I send an access token. If the token has not passed verification, then I save the config of the original request and make a request to update the tokens. If everything is fine, then I re-send the original request. The problem is that the original request is sent with the old token. Tell me how I can update the value in headers.Authorization?
import axios from 'axios'
import { setAccessToken } from '../store/authSlice'
export const axiosConfig = (accessToken: any, dispatch: any) => {
const API_URL = 'http://localhost:3001/api'
const $api = axios.create({
withCredentials: false,
baseURL: API_URL
})
$api.interceptors.request.use((config) => {
config.headers!.Authorization = `Bearer ${accessToken}`
return config
})
$api.interceptors.response.use(
(config) => {
return config
},
async (error) => {
const originalRequest = error.config
if (error.response.status === 403 && error.config && !error.config._isRetry) {
originalRequest._isRetry = true
try {
const response = await axios.get(`${API_URL}/auth/refresh-tokens`, {
withCredentials: false,
headers: {
Authorization: `Bearer ${localStorage.refreshToken}`
}
})
localStorage.setItem('refreshToken', response.data.refreshToken)
dispatch(setAccessToken(response.data.accessToken)) // new token
return $api.request(originalRequest) // <=== original request with old token
} catch (e) {
console.log('error')
}
}
throw error
}
)
return $api
}
You are using $api.interceptors.response.use() which is on the response not the request. You will not be able to change the Authorization header on a request that has already been sent.
I would use some type of error handler or axios response intercepter to direct user to the login page if they are expired/not logged in. Then I would have an error handler function that can try to attempt a re-authorization then have the error handler function resend the original request that would then have the updated Authorization token. But remember you still cant change the request that has already been sent.
myAxoisInstance.interceptors.request.use(
function (config) {
// This is run on each request so if you have or then update
the token for local storage your next request will get that updated token
const token = localStorage.getItem("token");
if (token) {
//Assign the token to the config
//If you need to send a request here to see if token is valid I don't recommend that. If you are using a JWT token you can check if it is expired here and do something else like a redirect to login.
config.headers!.Authorization = `Bearer ${token}`;
} else {
//Can retrieve and assign token here I typically like to do a redirect here as they are likely not logged or sesson expired. in or something like that. Then allow the sign-in process to add the token to the local storage.
}
return config;
},
function (error) {
return Promise.reject(error);
}
);
I have a get request in my Redux Async Thunk. After calling get to my node.js express server it sends a 304 status code, for some reason I can't get my data.
const userTokenAxios = axios.create({
baseURL: '/api/shoes',
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
},
});
userTokenAxios.interceptors.response.use((response) => {
if (response.data.errorMessage === 'jwt expired') {
localStorage.removeItem('token');
localStorage.removeItem('user');
}
});
export const getShoesAsync = createAsyncThunk(
'shoes/getShoesAsync',
async (payload, { rejectWithValue }) => {
try {
const response = await userTokenAxios.get('/');
console.log(response);
return response.data;
} catch (error) {
return rejectWithValue(error.response.data);
}
}
);
Its being called from my homepage:
useEffect(() => {
dispatch(getShoesAsync());
}, [dispatch]);
But I can't get any data as every time the page loads the server sends a 304
my backend controller:
exports.getAllShoes = async (req, res, next) => {
try {
let query = Shoe.find({});
const shoes = await query.populate([
{
path: 'user',
select: 'username',
},
]);
return res.status(200).json(shoes);
} catch (err) {
return next(err);
}
};
app.js in my backend folder:
// ROUTES
app.use('/auth', authRouter);
app.use(
'/api',
expressJwt({ secret: process.env.JWT_SECRET, algorithms: ['HS256'] })
);
app.use('/api/shoes', shoeRouter);
package.json in my client folder
"proxy": "http://localhost:9000"
My network preview:
The problem is your interceptor. Response interceptors must return a value, a rejected promise or throw an error, otherwise the resulting promise will resolve with undefined.
It also seems odd that you're intercepting token errors in the successful response interceptor. I would have assumed you'd use the error interceptor.
userTokenAxios.interceptors.response.use(
res => res, // success response interceptor
err => {
// usually you'd look for a 401 status ¯\_(ツ)_/¯
if (err.response?.data?.errorMessage === "jwt expired") {
localStorage.removeItem('token');
localStorage.removeItem('user');
}
return Promise.reject(err);
}
);
If you are actually responding with a 200 status for token errors, you'd need to handle it in the success interceptor
userTokenAxios.interceptors.response.use(
res => {
if (res.data.errorMessage === "jwt expired") {
localStorage.removeItem('token');
localStorage.removeItem('user');
// Make this look like an Axios error
return Promise.reject({
message: "jwt expired",
response: res,
});
}
return res;
}
);
It also looks like you don't need the trailing forward-slash in your request so simply use
const response = await userTokenAxios.get("");
I'm playing around with the Spotify Web API, and I'm trying to fetch my most played songs. I'm using the client credentials OAuth flow (you can read more about it at https://developer.spotify.com/documentation/general/guides/authorization/client-credentials/) to get an access token so that I can create requests. I'm getting the access token just fine, but when I try to fetch the data with the token, I'm getting a 403, indicating that my request is not being authorized.
Error code:
GET https://api.spotify.com/v1/me/top/tracks 403
I'm using React, so I'm fetching the data on page load with useEffect.
API File (spotify.ts)
import { Buffer } from 'buffer';
const clientId = "" // omitted for privacy
const clientSecret = "" // omitted for privacy
const getToken = async (): Promise<string> => {
const res = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
'Authorization': 'Basic ' + Buffer.from(clientId + ':' + clientSecret).toString('base64'),
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'client_credentials',
scope: 'user-top-read',
}),
});
const data = await res.json();
return data.access_token;
};
const getMostRecentSong = async (token: string) => {
const res = await fetch('https://api.spotify.com/v1/me/top/tracks', {
headers: {
'Authorization': `Bearer ${token}`,
},
});
const data = await res.json();
return data;
}
App.tsx
import React, { useEffect } from 'react'
import { getToken, getMostRecentSong } from './services/spotify'
const App = () => {
useEffect(() => {
const getData = async () => {
const accessToken = await getToken();
const data = await getMostRecentSong(accessToken);
console.log(data);
}
getData();
}, [])
return (
...
)
}
I've included my App.tsx file as well for convenience, but the only error I'm getting is with the request itself. Any help is greatly appreciated :)
The /me/top/{type} route requires the user-top-read scope, so using the Client Credentials flow will always result in an error. Here's a summary of the Client Credentials flow:
The Client Credentials flow is used in server-to-server authentication. Since this flow does not include authorization, only endpoints that do not access user information can be accessed.
Instead, you will need to use the Authorization Code flow and proxy the Spotify requests using a request mechanism that isn't restricted by CORS (e.g. a server or serverless function), or use the Implicit Grant flow which can be implemented without an additional cooperating process (you can do it all in your client React app).
I am trying to get basic information from Vimeo API about searched video by it's ID
I have Token Client Identifier and Secrets but Api documentation is pretty complicated
The question is how to make a simple call to fetch data?
I already tried with axios:
const GetByIdVimeo = async (ID) => {
const Token = 'MY_TOKEN'
const response = await axios.get({
url: `https://api.vimeo.com/videos/${ID}`,
Authorization: `bearer ${Token}`
}
)
const mofifiedResponse = {
resp: response
}
return mofifiedResponse
}
export default GetByIdVimeo
But response is 404 not Found status rejected
Thanks for help
The following code works.
First argument of axios.get() method is the url and the second a configuration object where you can specify your headers property. There you should place your authorization token.
const GetByIdVimeo = async (ID) => {
const Token = "YOUR_TOKEN";
const response = await axios.get(`https://api.vimeo.com/videos/${ID}`, {
headers: {
Authorization: `Bearer ${Token}`,
},
});
const mofifiedResponse = {
resp: response,
};
return mofifiedResponse;
};
export default GetByIdVimeo
Keep in mind that you have to generate an unauthenticated access token to access data this way. Otherwise you have to use OAuth to authenticate, which may be more complicated.
In my react app i am using axios to perform the REST api requests.
But it's unable to send the Authorization header with the request.
Here is my code:
tokenPayload() {
let config = {
headers: {
'Authorization': 'Bearer ' + validToken()
}
}
Axios.post(
'http://localhost:8000/api/v1/get_token_payloads',
config
)
.then( ( response ) => {
console.log( response )
} )
.catch()
}
Here the validToken() method would simply return the token from browser storage.
All requests are having a 500 error response saying that
The token could not be parsed from the request
from the back-end.
How to send the authorization header with each requests? Would you recommend any other module with react?
const config = {
headers: { Authorization: `Bearer ${token}` }
};
const bodyParameters = {
key: "value"
};
Axios.post(
'http://localhost:8000/api/v1/get_token_payloads',
bodyParameters,
config
).then(console.log).catch(console.log);
The first parameter is the URL.
The second is the JSON body that will be sent along your request.
The third parameter are the headers (among other things). Which is JSON as well.
Here is a unique way of setting Authorization token in axios. Setting configuration to every axios call is not a good idea and you can change the default Authorization token by:
import axios from 'axios';
axios.defaults.baseURL = 'http://localhost:1010/'
axios.defaults.headers.common = {'Authorization': `bearer ${token}`}
export default axios;
Some API require bearer to be written as Bearer, so you can do:
axios.defaults.headers.common = {'Authorization': `Bearer ${token}`}
Now you don't need to set configuration to every API call. Now Authorization token is set to every axios call.
You can create config once and use it everywhere.
const instance = axios.create({
baseURL: 'https://example.com/api/',
timeout: 1000,
headers: {'Authorization': 'Bearer '+token}
});
instance.get('/path')
.then(response => {
return response.data;
})
The second parameter of axios.post is data (not config). config is the third parameter. Please see this for details: https://github.com/mzabriskie/axios#axiosposturl-data-config
By using Axios interceptor:
const service = axios.create({
timeout: 20000 // request timeout
});
// request interceptor
service.interceptors.request.use(
config => {
// Do something before request is sent
config.headers["Authorization"] = "bearer " + getToken();
return config;
},
error => {
Promise.reject(error);
}
);
If you want to some data after passing token in header so that try this code
const api = 'your api';
const token = JSON.parse(sessionStorage.getItem('data'));
const token = user.data.id; /*take only token and save in token variable*/
axios.get(api , { headers: {"Authorization" : `Bearer ${token}`} })
.then(res => {
console.log(res.data);
.catch((error) => {
console.log(error)
});
Just in case someone faced the same issue.
The issue here is when passing the header without data, the header's configuration will be in the payload data, So I needed to pass null instead of data then set the header's configuration.
const config = {
headers: {
"Content-type": "application/json",
"Authorization": `Bearer ${Cookies.get("jwt")}`,
},
};
axios.get(`${BASE_URL}`, null, config)
This works and I need to set the token only once in my app.js:
axios.defaults.headers.common = {
'Authorization': 'Bearer ' + token
};
Then I can make requests in my components without setting the header again.
"axios": "^0.19.0",
I use a separate file to init axios instance and at the same time, I add intercepters to it. Then in each call, the intercepter will add the token to the request header for me.
import axios from 'axios';
import { getToken } from '../hooks/useToken';
const axiosInstance = axios.create({
baseURL: process.env.REACT_APP_BASE_URL,
});
axiosInstance.interceptors.request.use(
(config) => {
const token = getToken();
const auth = token ? `Bearer ${token}` : '';
config.headers.common['Authorization'] = auth;
return config;
},
(error) => Promise.reject(error),
);
export default axiosInstance;
Here is how I use it in the service file.
import { CancelToken } from 'axios';
import { ToolResponse } from '../types/Tool';
import axiosInstance from './axios';
export const getTools = (cancelToken: CancelToken): Promise<ToolResponse> => {
return axiosInstance.get('tool', { cancelToken });
};
// usetoken is hook i mad it
export const useToken = () => {
return JSON.parse(localStorage.getItem('user')).token || ''
}
const token = useToken();
const axiosIntance = axios.create({
baseURL: api,
headers: {
'Authorization':`Bearer ${token}`
}
});
axiosIntance.interceptors.request.use((req) => {
if(token){
req.headers.Authorization = `Bearer ${token}`;
}
return req;
})
If you are sending a post request with empty data remember to always set the second parameter to either empty object or empty string just as in the example below. e.g: axios.post('your-end-point-url-here', '', config)
if you don't set it axios will assume that whatever you are passing as the second parameter is a formData
const config = {
headers: { Authorization: `Bearer ${storage.getToken()}` }
};
axios
.post('http://localhost:8000/api/v1/get_token_payloads', {}, config)
.then(({ data: isData }) => {
console.log(isData);
})
.catch(error => {
console.log(error);
});
You must mention the 2nd parameter body for the post request even if it is empty, try this :
tokenPayload() {
let config = {
headers: {
'Authorization': 'Bearer ' + validToken()
}
}
Axios.post(
'http://localhost:8000/api/v1/get_token_payloads',
// empty body
{},
config
)
.then( (response) => {
console.log(response)
} )
.catch()
}
You can try configuring the header like this:
const headers = {"Content-Type": "text/plain", "x-access-token": token}
You can use interceptors in axios:
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
More on that you can find here: https://axios-http.com/docs/interceptors
there are a lot of good solution but I use this
let token=localStorage.getItem("token");
var myAxios=axios.create({
baseURL: 'https://localhost:5001',
timeout: 700,
headers: {'Authorization': `bearer ${token}`}
});
export default myAxios;
then i import myaxios to my file and
myAxios.get("sth")
axios by itself comes with two useful "methods" the interceptors that are none but middlewares between the request and the response. so if on each request you want to send the token. Use the interceptor.request.
I made apackage that helps you out:
$ npm i axios-es6-class
Now you can use axios as class
export class UserApi extends Api {
constructor (config) {
super(config);
// this middleware is been called right before the http request is made.
this.interceptors.request.use(param => {
return {
...param,
defaults: {
headers: {
...param.headers,
"Authorization": `Bearer ${this.getToken()}`
},
}
}
});
this.login = this.login.bind(this);
this.getSome = this.getSome.bind(this);
}
login (credentials) {
return this.post("/end-point", {...credentials})
.then(response => this.setToken(response.data))
.catch(this.error);
}
getSome () {
return this.get("/end-point")
.then(this.success)
.catch(this.error);
}
}
I mean the implementation of the middleware depends on you, or if you prefer to create your own axios-es6-class
https://medium.com/#enetoOlveda/how-to-use-axios-typescript-like-a-pro-7c882f71e34a
it is the medium post where it came from