React - Handle jwt auth fail using await fetch - node.js

I wrote an API that do some stuff, and I protect this using a jwt token.
This is the function for check the validity (checkAuth):
module.exports = (req, res, next) => {
try {
const token = req.headers.authorization;
const decoded = jwt.verify(token, process.env.TOKEN_SECRET);
req.userData = decoded;
next();
}
catch (error) {
return res.status(401).json({
message: 'Auth failed'
});
}
};
And I define the route of the API in this way:
router.post('/myAPI', checkAuth, MyAPIDefinition);
When I try to fetch the API, using an expired jwt I can't get the response of the checkAuth. This is my API call using await fetch:
const response = await fetch(`${API_URI_DEV}/myAPI`, {
method: 'POST',
body: JSON.stringify({encod: { content: data }}),
headers: {
'Content-Type': 'application/json; charset=utf-8',
Accept: 'application/json',
'authorization': jwt
}
});
The content of response is undefined.

Related

Auth0 sync userinfo

I'm trying to sync my auth0 userinfo with my local database:
userRouter.get("/sync", validateAccessToken, (req, res) => {
var request = require("request");
var usertoken;
var options = { method: 'POST',
url: 'https://MYDOMAN.eu.auth0.com/oauth/token',
headers: { 'content-type': 'application/json' },
body: '{"client_id":"myclienttoken","client_secret":"myclientsecret","audience":"https://MYDOMAIN.eu.auth0.com/api/v2/","grant_type":"client_credentials"}' };
request(options, function (error, response, body) {
if (error) throw new Error(error);
usertoken = body;
console.log(body);
});
var auth0options = {
method: "GET",
url: "https://MYDOMAIN.eu.auth0.com/api/v2/users",
params: {id: 'email:"testuser"', search_engine: 'v3'},
headers: {
"content-type": "application/json",
authorization: `Bearer` + usertoken.access_token,
},
};
axios.request(auth0options).then(function (response) {
console.log("RES DATA: ", response.data);
})
.catch(function (error) {
console.error(error);
});
console.log("called");
res.status(200).json("message");
});
The following line, results in a error:
authorization: Bearer + usertoken.access_token,
"Cannot read properties of Undefined (reading 'access_token)"
But I don't get the userinfo when calling the auth0 api with that token.
I'm using the audience from the Auth0 Management API ex:
https://MYDOMAIN.eu.auth0.com/api/v2/
And not the audience from my own API, as I have read that's the correct way:
https://mydomain
Any ideas on what I'm doing wrong?

React.js Passport Authentication unable to get req.user from client

I am trying to authenticate a user through some API configured with passportjs. When I run the authentication request I get the redirect to the success route, but I can't get req.user. I tried through Postman and it works. I don't know what I'm forgetting. Could anyone help me?
This is my success route:
app.get("/success", async (req, res) => {
if (req.user){
return res.status(200).json({
user: req.user,
message: "Logged"
});
}
else {
return res.status(401).json({
message: "User authentication failed"
});
}
});
This is my react code:
const handleSubmit = (e) => {
e.preventDefault();
fetch("http://127.0.0.1:3001/login", {
method:"POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
},
redirect: "follow",
body: JSON.stringify({email: email, password: password})
}).then(resp => {
return resp.json();
}).then(data => console.log(data))
}
While you are calling the success/ route you need to add the authorization header along with the fetch request. We need to add the Basic jwt | authentication token as the authorization key
const response = await fetch(apiURL, {
method: 'GET',
headers: {
'Content-type': 'application/json',
'Authorization': `Bearer ${token}`,
// add the basic jwt | drf token for Authorization Key
},
body: JSON.stringify(yourNewData)
})

JWT Full Stack Verify Token Not Working to Frontend

I have an API in which uses VerifyToken authentication with JWT. This works through postman, however it appears there's an issue passing this through to the frontend to ensure the token is verified.
For one, I have a code block to create verifyToken:
const verifyToken = (req, res, next) => {
const authHeader = req.headers.token;
if (authHeader) {
const token = authHeader.split(" ")[1];
jwt.verify(token, process.env.JWT_SEC, (err, user) => {
if (err) res.status(403).json("Token is not valid!");
req.user = user;
next();
});
} else {
return res.status(401).json("You are not authenticated!");
}
};
If I run the following in Postman, it works all good, header and all.
localhost:5000/api/users/updateUser/62a9be62a8262145b72feee9
This is then handled in requestMethods,
import axios from "axios";
const BASE_URL = "http://localhost:5000/api/";
const user = JSON.parse(localStorage.getItem("persist:root"))?.user;
const currentUser = user && JSON.parse(user).currentUser;
const TOKEN = currentUser?.accessToken;
export const publicRequest = axios.create({
baseURL: BASE_URL,
});
export const userRequest = axios.create({
baseURL: BASE_URL,
bearer: { token: `Bearer ${TOKEN}` },
});
However when I pass this to the frotnend, for example through a request like this,
const updateUser = async () => {
//include all in the state earlier with spread
//update only position, which is input
userRequest.put(`users/updateUser/${user._id}`, userData);
console.log('your data has updated to', userData)
//include the put request here for API
}
I am now getting an error for a 401: Error: Request failed with status code 401
It appears the token isn't being passed to the frontend correctly. What am I doing wrong?
Passing token in headers in Axios is not tuned correctly. Notice the headers config.
export const userRequest = axios.create({
baseURL: BASE_URL,
headers: { token: `Bearer ${TOKEN}` },
});
Another way to pass the token is where you are calling the API:
const updateUser = async () => {
//include all in the state earlier with spread
//update only position, which is input
userRequest.put(`users/updateUser/${user._id}`, userData, {
headers: {token: `Bearer ${TOKEN}`}
});
console.log('your data has updated to', userData)
//include the put request here for API
}
Here is another tip: in your auth middleware by detecting a wrong token, do not go to next and return!
const verifyToken = (req, res, next) => {
const authHeader = req.headers.token;
if (authHeader) {
const token = authHeader.split(' ')[1];
jwt.verify(token, process.env.JWT_SEC, (err, user) => {
if (err) {
res.status(403).json('Token is not valid!');
return;
} else {
req.user = user;
next();
}
});
} else {
return res.status(401).json('You are not authenticated!');
}
};

Set-Cookie not sended on HTTP response header

i´m creating a Authentication page with React and Express. I'm using JWT too.
I´ve made this route in the back:
server.js
...
app.use(
cookieSession({
name: "prode_session",
secret: "MIOURI_PRODE_SECRET", //add to .env variable
httpOnly: false,
})
);
app.use(cors());
...
auth.routes.js
app.post("/signin", controller.signin);
user.routes.js
app.get(
"/user",
[authJwt.verifyToken],
(req, res) => res.send(true)
)
auth.controller.js
exports.signin = async (req, res) => {
const user = await Users.findOne({
where: { email: req.body.email },
});
try {
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
const passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({
message: "Invalid Password!",
});
}
const token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 84000, //24hours
});
req.session.token = token;
console.log(req.session);
return res.status(200).send({
isLogged: true,
id: user.id,
email: user.email,
suscripcion: user.suscripcion,
preference_id: user.preference_id,
token,
});
} catch (error) {
console.log(error);
}
};
authJWT.js
verifyToken = async (req, res, next) => {
let token = req.session.token;
console.log(`THIS IS THE TOKEN: ${token}`);
if (!token) {
return res.status(403).send({
message: "No token provided",
});
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
console.log(err);
return res.status(401).send({
message: "Unauthorized!",
});
}
req.id = decoded.id;
next();
});
};
const authJwt = { verifyToken };
module.exports = authJwt;
When I test this with POSTMAN, it works Ok, I mean, if first I try to make the GET request, the response is "No token provided", but if I signin first, generate the token and then make the GET request, I get true.
The problem is when I try to implement this in the front.
I have this Login component in React in which I make a POST request with the credentials:
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await fetch("http://localhost:3000/signin", {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
body: JSON.stringify({
email,
password,
}),
});
const data = await response.json();
console.log(data);
if (data.isLogged && data.suscripcion === true && data.token) {
await tokenAvailable()
//navigate(`/masthead/${email}&${data.isLogged}&${data.id}`);
} else if (data.isLogged && data.suscripcion === false) {
navigate("/suscripcion", {
state: { preference_id: data.preference_id },
});
} else {
window.alert("Invalid Login");
}
} catch (error) {
console.log(error);
}
};
async function tokenAvailable() {
const user = await fetch("http://localhost:3000/user", {
method: "GET",
mode: "cors",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
});
const response = await user.json();
setUser(await response);
console.log(await response);
return response;
}
When I make the POST, the GET request is executed (tokenAvailable function) after receiving the response, but I receive "No token Provided" while I expect to receive "true" as in Postman.
From what I debug, the authJWT.js file, is not receiving nothing from the req.session.token.
When I compare the headers from postman and the browser, in postan the SET-cookie key appears, but in the browser not.
postman:
browser:
I need some help here. I´ve been strugling with this for almost 3 days.
I found a solution for this. Apparently, the HttpOnly Cookie approach works if the React app and the back-end server hosted in same domain. So we need to use http-proxy-middleware for local development.
I´ve tried to install the http-proxy-middleware but a lot of errors came, so I decided to store de JWT in the localstorage.

Node JS : Can't access to req.headers.authorization to extract JWT token

Hello I am trying to extract the JWT token from the Headers of my request, but this request does not contain an "Authorization" key with "Bearer xxxxx". I tried adding query parameters but it doesn't change anything ...
The goal is to create an authentication system with JWT. (I am a beginner)
The request :
const signup = async (e) => {
e.preventDefault();
await POST(ENDPOINTS.USER_SIGNUP, userSignup );
};
const login = async (e) => {
e.preventDefault();
await POST(ENDPOINTS.USER_LOGIN, userLogin);
};
In my controllers file :
exports.signup = async (req, res, next) => {
// ====== Password encryption =========
const saltRounds = 10;
const { user_password: password } = req.body;
const encryptedPassword = await bcrypt.hash(password, saltRounds);
// ====================================
const user = {
...req.body,
user_password: encryptedPassword,
};
const sql = "INSERT INTO users SET ?";
const query = db.query(sql, user, (err, result) => {
if (err) throw err;
console.log(result);
});
};
exports.login = (req, res, next) => {
//===== Check if user exists in DB ======
const { user_email, user_password: clearPassword } = req.body;
let sql = `SELECT user_password, user_id FROM users WHERE user_email=?`;
db.query(sql, [user_email], async (err, results) => {
console.log(results);
console.log(req.body);
if (err) {
return res.status(404).json({ err });
}
// ===== Verify password with hash in DB ======
const { user_password: hashedPassword, user_id } = results[0];
try {
const match = await bcrypt.compare(clearPassword, hashedPassword);
if (match) {
console.log("match ... user_id : ", user_id);
// If match, verify JWT token
res.status(200).json({
user_id: user_id,
token: jwt.sign({ userId: user_id }, "TOOOKEN", {
expiresIn: "24h",
}),
});
} else {
console.log("not match");
}
} catch (err) {
return res.status(400).json({ err: "une erreur" });
}
});
};
The middleware which will be the first code executed in my "routes" file to verify that the request has the correct token before being executing :
const jwt = require("jsonwebtoken");
require("dotenv").config();
module.exports = (req, res, next) => {
try {
console.log(req.headers);
const token = req.headers.authorization.split(" ")[1];
const decodedToken = jwt.verify(token, process.env.JWT_TOKEN);
const userId = decodedToken.user_id;
if (req.body.user_id && req.body.user_id !== userId) {
throw "Invalid user ID";
} else {
next();
}
} catch {
res.status(401).json({
error: new Error("Invalid user ID"),
});
}
};
If i console.log(req.headers) :
{
host: 'localhost:4200',
connection: 'keep-alive',
accept: 'application/json, text/plain, */*',
'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Mobile Safari/537.36',
'sec-gpc': '1',
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': 'fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7',
'if-none-match': 'W/"16a8-wyX3X/tr0d8x80MrYm6LBzAWEXg"'
}
If someone know how i can retrieve the token il the "authorization" key, it will be awesome !
If you wish, You can try axios as your HTTP client which can prevent mistakes. You can modify headers easily this way,
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
headers: {
'Authorization': 'Bearer <token>',
'X-Custom-Header': 'foobar'
}
});
// Send a POST request
instance.post<T>('/api', {
data, { configOptions }
});
check here https://github.com/axios/axios

Resources