Axios interceptors works really well for http://127.0.0.1:8000 local API calls. Here is the working code.
import axios from 'axios';
const http = axios.create({
baseURL: 'http://127.0.0.1:8000/api/',
Headers: {},
});
try {
http.interceptors.request.use(
(config) => {
let data = JSON.parse(localStorage.getItem('cyber-minds'));
if (data && data.user_status.token) {
config.headers['Authorization'] = 'Token ' + data.user_status.token;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
} catch (error) {
console.log(error);
}
export default http;
But after I deploy http://127.0.0.1:8000 to https://mysite-backend.herokuapp.com and replace my baseURL with https://mysite-backend.herokuapp.com it returns invalid token. here is the code which returns invalid token.
import axios from 'axios';
const http = axios.create({
baseURL: 'https://cyberminds-backend.herokuapp.com/api/',
Headers: {},
});
try {
http.interceptors.request.use(
(config) => {
let data = JSON.parse(localStorage.getItem('cyber-minds'));
if (data && data.user_status.token) {
config.headers['Authorization'] = 'Token ' + data.user_status.token;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
} catch (error) {
console.log(error);
}
export default http;
Here is local storage information.
{token: "e3746603ad6c8788b9936118f1fc36289bb20a8d", user: {id: 2,…},…}
assetRisk: "Low"
cid: 1
cpe: "cpe:2.3:a:oracle:peoplesoft_enterprise:8.22.14"
id: 2
name: ""
pid: 2
pr: "Windows"
token: "e3746603ad6c8788b9936118f1fc36289bb20a8d"
user: {id: 2,…}
user_status: {loggedIn: true, token: "e3746603ad6c8788b9936118f1fc36289bb20a8d"}
vendor: "Oracle"
The authentication is working very well. Authorization returns invalid token how can i resolve this issue?
Related
I have a quick question. I am using Axios to send requests to the nodejs API, when I set the token in the request header the API returns "jwt must be provided". The API expects the token with a custom name attached to it - here's how far I've gotten.
Snippet of API code that sends the token on login:
const token = jwt.sign(
{
userID: result[0].userID,
firstName: result[0].firstName,
lastName: result[0].lastName,
email: result[0].email,
role: result[0].role,
// exp: Math.floor(Date.now() / 1000) + 60 * 60,
},
"HeyImaPrivateKeyyy"
);
res.json({ token });
console.log("Login Attempt", res.statusMessage, req.body);
} else {
res.status(400).send({ message: "Invalid credentials!" });
console.log("Login Attempt", res.statusMessage, req.body);
}
-- React code from here --
Response from API on successful login:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOjEsImZpcnN0TmFtZSI6IkNhbWVyb24iLCJsYXN0TmFtZSI6IkVyYXNtdXMiLCJlbWFpbCI6ImNhbWVyb25AY2xpZnRjb2xsZWdlLmNvbSIsInJvbGUiOiJzdXBlckFkbWluIiwiaWF0IjoxNjYzMzEzNTM2fQ.9R6vXn-5Vb5fj48eUJGPNUGnXMw9TXOjJCox7U36WMI"
}
Saving the token on successful login (React)
const login = async ({ email, password }) => {
const res = await api.post(
"/auth",
{
email: email, //varEmail is a variable which holds the email
password: password,
},
{
headers: {
"Content-type": "application/json",
Authorization: false,
},
}
);
const { from } = state || {};
let token = jwt(res.data.token);
setToken("x-auth-token", token); // your token
localStorage.setItem("x-auth-token", res.data.token);
localStorage.setItem("userLogged", true);
localStorage.setItem("name", token.firstName);
localStorage.setItem("role", token.role);
navigate("/auth/dashboard" || from.pathname, { replace: true });
};
Here is the React component that is trying to call the API:
const [count, setCount] = useState(null);
const token = localStorage.getItem("x-auth-token");
const studentCount = useEffect(() => {
const config = {
headers: { "x-auth-token": token },
"Content-type": "application/json",
};
api.get("/students/", {}, config).then((response) => {
setCount(response.data);
});
}, [token]);
if (!count) return null;
This is what the API is expecting on request:
export const teacher = (req, res, next) => {
const token = req.header("x-auth-token");
if (!auth && !token)
return res.status(401).send({ message: "Access denied." });
const decoded = jwt.verify(token, "DemoPrivateKey");
if (auth && ["superAdmin", "admin", "teacher"].includes(decoded.role)) {
next();
} else {
res.status(400).send({ message: "Access denied!" });
}
};
Ideally, I would like to send the token as a header on successful login, but it saves as undefined on the client (have no idea how to fix that).
If you're using Axios then, as per the doc, get method should have config parameter in second position not third one.
So maybe, simply updating api.get("/students/", {}, config) into api.get("/students/", config) should solve your issue.
I have set up JWT to be set in localstorage whenever someone logins or registers. And it works, I can see the token in localstorage. But when I set the token in the headers with axios, node.js in the backend can`t find the token. Like it does not exists. I have checked it in the front end, I get logs of the token in the headers. And also when I request from postman it works. Here is the code.
setAuthToken function = {
const instance = axios.create({
baseURL: "https://localhost:5000",
});
if (token) {
instance.defaults.headers.common["x-auth-token"] = `${token}`;
console.log(instance.defaults.headers.common["x-auth-token"]);
} else {
delete instance.defaults.headers.common["x-auth-token"];
}
}
const loadUser = async () => {
if (localStorage.token) setAuthToken(localStorage.token);
console.log(localStorage.token);
try {
const res = await axios.get("/api/users");
console.log(res);
dispatch({ type: USER_LOADED, payload: res.data });
} catch (err) {
console.log(err.response.data.msg);
dispatch({ type: AUTH_ERROR });
}
The request comes to the await axios statement and goes to catch so error is in the request.
Here is the backend code
// Get current user
router.get("/", auth, async (req, res) => {
try {
const user = await User.findById(req.user.id);
res.status(200).json({ user });
} catch (err) {
console.log(err);
res.status(500).json({ msg: `Server Error` });
}
});
auth middleware function here = {
const token = req.headers["x-auth-token"];
console.log(token, "token in auth.js");
console.log(req.headers, "req.header");
if (!token) {
return res.status(401).json({ msg: `Access denied.` });
}
try {
const decoded = jwt.verify(token, config.get("jwtSecret"));
req.user = decoded.user;
next();
} catch (err) {
res.status(401).json({ msg: `Token is not valid` });
}
}
I`m new to backend develoment and axios. Can someone help me please. Thank you
Here are the console.logs
Logs
Logs
Little update, it looks like there is a problem with proxy, I am using my own backend api, and also movie data base api. So maybe thats why I cant set headers? Here are new logs:
config: Object { url: "/api/users", method: "get", timeout: 0, … }
data: "Proxy error: Could not proxy request /api/users from localhost:3000 to http://localhost:5000/ (ECONNREFUSED)."
headers: Object { connection: "keep-alive", date: "Wed, 05 May 2021 13:18:05 GMT", "keep-alive": "timeout=5", … }
request: XMLHttpRequest { readyState: 4, timeout: 0, withCredentials: false, … }
status: 500
statusText: "Internal Server Error
I think the issue is because you are setting you are setting up your instance wrongly
set up your instance in a new file config.js -
import Axios from 'axios';
const baseURL = "http://localhost:5000";
const axiosInstance = Axios.create({
baseURL: baseURL,
});
axiosInstance.interceptors.request.use(
function (config) {
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = 'Bearer ' + token;
}
return config;
},
function (error) {
return Promise.reject(error);
}
);
export default axiosInstance;
now when making any api request instead of using axios use axiosInstance eg-
axiosInstance.get('/something').then(res => console.log(res)).catch(err => console.log(err))
I had an issue where I couldn't specify URI when sending custom headers to my backend server with { ApolloClient } from 'apollo-boost',
So I had to use { ApolloClient } from 'apollo-client' instead.
That issue was fixed, but now my mutations aren't being sent to the backend?
My mutation :
import { gql } from 'apollo-boost';
export const LOGIN_USER = gql`
mutation($email: String!, $password: String!) {
loginUser(email: $email, password: $password) {
userId
token
expiresIn
}
}
`
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';
import { InMemoryCache } from 'apollo-cache-inmemory';
const httpLink = new HttpLink({
uri: 'http://localhost:3001/graphql'
})
const authLink = setContext((_, { headers }) => {
const store = JSON.parse(sessionStorage.getItem('interdevs-data'));
const token = store.token;
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
}
}
});
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
const login = async (email, password) => {
try {
const user = await loginUser({
variables: {
email,
password
}
});
const { userId, token, expiresIn } = user.data.loginUser;
setUserData({
token: token,
userId: userId,
expiresIn: expiresIn
});
sessionStorage.setItem('interdevs-data', JSON.stringify({
"token": token,
"userId": userId,
"expiresIn": expiresIn
}));
} catch(err) {
console.log('login error: ', err);
setLoginErr(err);
};
};
This is the error I'm getting.
"Error: Network error: Cannot read property 'token' of null"
When I switch it back importing ApolloClient from apollo-boost it works again.
Any help greatly appreciated!
Not 100% sure, but I think the error lies here:
const store = JSON.parse(sessionStorage.getItem('interdevs-data'));
const token = store.token;
If there are no items with the key interdevs-data, store will be null.
I think you can fix it by doing this:
const store = JSON.parse(sessionStorage.getItem('interdevs-data'));
const token = store ? store.token : null;
found out how to set auth headers with apollo-boost
const client = new ApolloClient({
uri: 'http://localhost:3001/graphql',
request: operation => {
const ssData = JSON.parse(sessionStorage.getItem('data'));
operation.setContext({
headers: {
authorization: ssData ? `Bearer ${ssData.token}` : ''
}
});
}
});
I'm running Vue.js and axios and are trying to make a generic API object like the following:
import router from './router'
import auth from './auth'
const axios = require('axios')
export const API = axios.create({
baseURL: `https://my-api.com/`,
headers: {
Authorization: auth.getToken()
}
})
API.interceptors.response.use(null, function (error) {
if (error.response.status === 401) {
console.log('Failed to login')
router.push('/Login')
}
return Promise.reject(error)
})
I'm trying to have the users redirected to the Login screen in my single page app, whenever a 401 error code is received.
But I'm not getting redirected, and no error occurs in my Developer Tools in Chrome. I do get the console.log with Failed to login.
I have detected a similar situation. I haved fixed with this code:
import router from 'router'
import store from 'store'
...
...
axios.interceptors.response.use(function (response) {
return response
}, function (error) {
console.log(error.response.data)
if (error.response.status === 401) {
store.dispatch('logout')
router.push('/login')
}
return Promise.reject(error)
})
You can do something like follow:
axios.post("quote", params)
.catch(function(error) {
if (error.response && error.response.status === 401) {
window.location.href = "logon";
} else {
// Handle error however you want
}
});
Source: https://github.com/axios/axios/issues/396#issuecomment-395592900
you Can use below code and add httpClient.js file to your project:
import axios from 'axios';
import {
authHeader
}
from '../helper'
const baseUrl = 'http://localhost:8811/api/';//local-test
const Api_Path = `${baseUrl}/`;
const httpClient = axios.create({
baseURL: Api_Path,
headers: {
//Authorization: 'Bearer {token}',
//timeout: 1000, // indicates, 1000ms ie. 1 second
"Content-Type": "application/json",
}
})
const authInterceptor = (config) => {
config.headers['Authorization'] = authHeader();
return config;
}
const errorInterceptor = error => {
// check if it's a server error
if (!error.response) {
//notify.warn('Network/Server error');
console.error('**Network/Server error');
console.log(error.response);
return Promise.reject(error);
}
// all the other error responses
switch (error.response.status) {
case 400:
console.error(error.response.status, error.message);
//notify.warn('Nothing to display', 'Data Not Found');
break;
case 401: // authentication error, logout the user
//notify.warn('Please login again', 'Session Expired');
console.error(error.response.status, error.message);
localStorage.removeItem('token');
localStorage.removeItem('user');
//router.push('/auth');
break;
default:
console.error(error.response.status, error.message);
//notify.error('Server Error');
}
return Promise.reject(error);
}
httpClient.interceptors.request.use(authInterceptor);
httpClient.interceptors.response.use(responseInterceptor, errorInterceptor);
export default httpClient;
I am using a JWT Token auth system, and when I login I get the token like this:
axios.post('/login', data)
.then(response => {
localStorage.setItem('token', response.data.token);
});
This works well and the token is saved in localStorage. However, the token is not included in the later requests. The Authorization header is Bearer null.
This is how I set up my global axios object.
window.axios = axios.create({
baseURL: '/api/',
timeout: 10000,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-TOKEN': document.head.querySelector('meta[name="csrf-token"]').content,
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
});
If I refresh the site, the token is set, and is used properly.
Edit:
I got it to work by removing the Authorization header from the create() method and instead using window.axios.defaults.headers.common['Authorization']. But now the same problem appears with Laravel Echo. I create the instance like this:
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'xxx',
cluster: 'eu',
encrypted: true,
namespace: 'xxx',
auth: {
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
}
});
And I update the header like this:
window.setAuthToken = (token) => {
window.axios.defaults.headers.Authorization = 'Bearer ' + token;
window.Echo.options.auth.headers.Authorization = 'Bearer ' + token;
localStorage.setItem('token', token);
}
The axios header is successfully updated, but not Echo.
Use axios interceptors for this purpose. It will run for every request call.
Better to keep axios methods in a separate file and make call to it than using it directly in all components. This way we can replace axios with another library if we want with minimal effort. Here's what I'm doing in my project.
import axios from "axios";
import AuthService from "./auth";
import config from '../config'
const instance = axios.create({
baseURL: config.apiServer.url,
timeout: config.apiServer.timeout
});
instance.interceptors.request.use(
config => {
const token = AuthService.getToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
error => Promise.reject(error)
);
const ApiService = {
get(url) {
return instance.get(url)
.then(res => res)
.catch(reason => Promise.reject(reason));
},
post(url, data) {
return instance.post(url, data)
.then(res => res)
.catch(reason => Promise.reject(reason));
},
awaitAll() {
return axios.all(Array.from(arguments))
.then(axios.spread((...responses) => responses))
.catch(reasons => Promise.reject(reasons));
}
};
export default ApiService;
Now to use it in a component:
ApiService.get(YOUR_GET_URL)
.then(res => {
Console.log(res);
))
.catch(reason => {
console.log(reason);
})
The problem is that your are using localStorage.getItem('token') at page load. When you are setting it in localStorage, you have to update it in axios header.
window.axios = axios.create({
baseURL: '/api/',
timeout: 10000,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-TOKEN': document.head.querySelector('meta[name="csrf-token"]').content,
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
});
axios.post('/login', data)
.then(response => {
localStorage.setItem('token', response.data.token);
window.axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('token');
});
I faced the same problem before and I found out that the file that contains my axios config was being loaded at the time of storing the token, so it was accessing it before it is stored.
The solution is, in axios config:
const axiosInstance = axios.create({
baseURL: `${API_BASE_URL}`,
headers: {
Accepted: 'appication/json',
'Content-Type': 'application/json',
},
});
axiosInstance.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.authorization = token;
}
return config;
},
(error) => Promise.reject(error),
);
export default axiosInstance;
After that, use this instance where you need to make a request.