I am having troubles implementing the signin side of an authentication system with React, Axios and Express (the signup functionality works fine), I have already taken a look at multiple similar questions with different answers but none seem to work, my approach is the following:
In my Node backend I have:
router.post('/sign-in', async (req, res) => {
let email = req.body.email;
let password = req.body.password;
let user = await User.findOne({ email: email });
if (user && bcryptjs.compareSync(password, user.password)) {
jwt.sign({ user_id: user.user_id }, config.app.secretKey, { expiresIn: 60 * 60 * 24 * 7 }, (err, token) => {
console.log(token);
return res.send(token);
});
} else {
return res.send({ "error": "Wrong email or password." });
}
});
function isAuthenticated(req, res, next) {
const bearerHeader = req.headers['Authorization'];
console.log(bearerHeader);
if (typeof bearerHeader !== 'undefined') {
req.token = bearerToken;
next();
} else {
res.sendStatus(401);
}
}
In the React I have a sign-in component with a signin method:
signin() {
let email = document.getElementById("email").value;
let password = document.getElementById("password").value;
let account = { email, password };
axios.post("http://localhost:4000/auth/sign-in", account).then((token) => {
localStorage.setItem("token", token.data);
console.log(token.data);
axios.defaults.headers.common['Authorization'] = token.data;
//window.location = "/";
});
}
I am checking if the authentication works by executing the following code:
componentDidMount() {
console.log(localStorage.getItem("token"));
const token = localStorage.getItem("token");
if (token) {
axios.defaults.headers.common['Authorization'] = localStorage.getItem("token");
axios.get("http://localhost:4000/authorized",{withCredentials:true}).then((response)=>{
console.log(response);
});
}
}
The /authorized api is the following:
app.get("/authorized", auth.isAuthenticated, (req,res)=>{
res.send("Authorized!");
});
This is the server app:
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const mongoose = require('mongoose');
const config = require('./config');
mongoose.connect(config.database.host); // { autoIndex: false } set this to false in production to disable auto creating indexes
mongoose.Promise = global.Promise;
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const mongoose = require('mongoose');
const config = require('./config');
mongoose.connect(config.database.host); // { autoIndex: false } set this to false in production to disable auto creating indexes
mongoose.Promise = global.Promise;
const app = express();
app.use(helmet());
app.use(cors( { origin:'http://localhost:3000', credentials:true } ));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
const auth = require('./services/authentication');
app.use("/auth", auth.router);
app.get("/authorized", auth.isAuthenticated, (req,res)=>{
res.send("Authorized!");
});
app.listen(4000,()=>{
console.log('Server started...');
});
The problem is the following: when the user sends a request to /sign-in it correctly receives the token and stores it in localStorage (at the moment I am storing it in the localStorage maybe later on I will probably store it in a cookie), but when the token is sent to the server for authorization purposes the server executes the isAuthenticated method which replies with a 401 status, I have tried almost everything but I cannot manage to find a solution.
This is what I get when logging req.headers:
{
host: 'localhost:4000',
connection: 'keep-alive',
pragma: 'no-cache',
'cache-control': 'no-cache',
'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"',
accept: 'application/json, text/plain, */*',
'sec-ch-ua-mobile': '?1',
'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Mobile Safari/537.36',
'sec-ch-ua-platform': '"Android"',
origin: 'http://localhost:3000',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:3000/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7'
}
CodePudding user response:
You are using isAuthenticated method as a middleware I suppose. It is supposed to be called after sign-in. In the router.post('/sign-in') I don't think you need this middleware isAuthenticated to be executed. remove the middleware from the signing router. It should be working fine after that. Signing in the user will generate a token which you store in the header to authenticate the user. Not signing router itself. Hope you find this helpful. Best of luck.
CodePudding user response:
On server side, update CORS code like so :-
app.use(cors( { origin:'http://localhost:3000', credentials:true } ));
On client side, add withCredentials:true like so :-
componentDidMount() {
console.log(localStorage.getItem("token"));
axios.get("http://localhost:4000/authorized",{withCredentials:true}).then((response)=>{
console.log(response);
}).catch((error)=>{
console.log(error);
});
}
