-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Setting the headers on global axios does not work #28
Comments
@mmahalwy I had a similar issue; As far as I can tell you can set the headers, but your underlying problem is that devise_token_auth itself changes the token on each request to the API. Therefore the headers change at each request. Solution: Other packages like redux-auth (now outdated) wrap fetch/axios in order to re-set the headers on each request. You could do that yourself or set
Hope helps! |
@fkotsian yeah, that might be a solution. I think perhaps this library should be request-library agnostic (maybe I want to use |
Hm. Just kidding now. I'm looking and I don't seem to have access to the headers on axios at all. 👎 |
For future reference: copied solution from here - axios/unable to set or override global headers
Yes this creates new axios instances on each action, would love thoughts on how to clean up. |
@fkotsian I'd recommend doing this actually: // ./utils/auth.js
export const setupInterceptors = () => {
axios.interceptors.request.use(
(config) => {
// eslint-disable-next-line
config.headers = {
...config.headers,
'access-token': store.get('auth')['access-token'],
client: store.get('auth').client,
uid: store.get('auth').uid,
};
return config;
},
error =>
// Do something with request error
Promise.reject(error),
);
axios.interceptors.response.use(
(response) => {
if (response.headers['access-token']) {
setAuthHeaders(response.headers);
persistAuthHeadersInDeviceStorage(response.headers);
}
return response;
},
error =>
// Do something with response error
Promise.reject(error),
);
};
// wherever you'd like to use this
setupInterceptors(); Granted, I ended up rewriting some of this package for my own use in my own app, so I am using the |
Whoa, had no idea about interceptors! I like it! |
Just in case someone was trying both approaches, this is what I came up with. A few differences with my approach (might be what @mmahalwy had in mind):
import axios from 'axios';
import storage from 'redux-persist/lib/storage/index';
import { persistor, store } from '../configureStore';
import {
setAuthHeaders,
persistAuthHeadersInDeviceStorage
} from './auth-tools';
/* Setup Keys Constant */
const authHeaderKeys = [
'access-token',
'token-type',
'client',
'expiry',
'uid'
];
/* Utility Function to create header object from Storage
* @returns {object}
*/
async function getHeadersFromStorage() {
return {
'access-token': await storage.getItem('access-token'),
client: await storage.getItem('client'),
uid: await storage.getItem('uid'),
expiry: await storage.getItem('expiry')
};
}
/*
* The function that subscribes to our redux store changes
* Sets up new api headers for the global axios settings.
* https://github.com/axios/axios#global-axios-defaults
* Caveat - this will change the headers for every axios request
* not just the one used for the api instance.
*/
function setNewApiHeaders() {
getHeadersFromStorage().then(headers => {
authHeaderKeys.forEach(key => {
axios.defaults.headers.common[key] = headers[key];
});
});
}
/*
* Adds a change listener. https://redux.js.org/api/store#subscribe-listener
* It will be called any time an action is dispatched, and some
* part of the state tree may potentially have changed. You may then
* call getState() to read the current state tree inside the callback.
*/
store.subscribe(() => setNewApiHeaders());
/*
* Setups up a new instance of axios.
* https://github.com/axios/axios#creating-an-instance
*
*/
const api = axios.create({
// baseURL: '/api/v1',
headers: {
'Content-Type': 'application/json'
}
});
/*
* Axios Request Interceptor.
* Before each request, use the values in local storage to set new headers.
*/
api.interceptors.request.use(
async config => {
const newConfig = config;
const newHeaders = await getHeadersFromStorage();
newConfig.headers = {
...config.headers, // Spread config headers
...newHeaders // Spread new headers
};
return newConfig;
},
error =>
// Reject the promise
Promise.reject(error)
);
/*
* Axios Respose Interceptor.
* After each response, use the values in local storage to set new headers.
*/
api.interceptors.response.use(
async response => {
// Only change headers when access-token is returned in response
if (response.headers['access-token']) {
await setAuthHeaders(response.headers);
await persistAuthHeadersInDeviceStorage(response.headers);
}
return response;
},
error =>
// Reject the promise
Promise.reject(error)
);
// Uncomment (for testing) to use the api in the console
if (typeof window !== 'undefined') {
window.consoleApi = api;
}
export default api;
And these are the two customized tools
import axios from 'axios';
import storage from 'redux-persist/lib/storage/index';
const authHeaderKeys = [
'access-token',
'token-type',
'client',
'uid',
'expiry'
];
export const setAuthHeaders = headers => {
authHeaderKeys.forEach(key => {
storage.getItem(key).then(fromStorage => {
const value = headers[key] || fromStorage;
axios.defaults.headers.common[key] = value;
});
});
};
export const persistAuthHeadersInDeviceStorage = headers => {
authHeaderKeys.forEach(key => {
storage.getItem(key).then(fromStorage => {
const value = headers[key] || fromStorage;
storage.setItem(key, value);
});
});
}; |
Seems that either:
The text was updated successfully, but these errors were encountered: