How to send cookies with fetch and fix 404 post error? - node.js

How to send cookies with fetch and fix 404 post error?
Hello. I'm trying to send a post to a server that uses a jwt token for authorization, but I get a post 404.
Here is the logic for setting the token and the user:
app.use((req, res, next)=>{
const jwtToken = req.cookies.JWT_TOKEN;
if(!jwtToken) {
next();
return;
}
jwt.verify(jwtToken, SECRET, (err, decoded)=>{
if(err) {
next(err);
return;
}
const sessionData = decoded.data;
let userId;
if (sessionData['modx.user.contextTokens']) {
if (sessionData['modx.user.contextTokens']['web'] > 0) {
userId = sessionData['modx.user.contextTokens']['web'];
}else if($dataarr['modx.user.contextTokens']['mgr'] > 0) {
userId = sessionData['modx.user.contextTokens']['mgr'];
} else {
return redirect('/signin');
}
}
req.user = {userId};
next();
});
});
app.use((req, res, next)=>{
if (!req.user || !req.user.userId) {
next(new Error('Access Denied'));
} else {
next();
}
});
Here is the get request that was already here and it works:
app.get("/:id?", function(req, res){
const room = {id:parseInt(req.params.id||0)};
const userid = req.user.userId;
console.log('USEEEEEEEEEEEEEEEEEEEEEEEEEER ID', userid);
pool.query("SELECT * FROM modx_user_attributes WHERE id = ?", [userid], function(err, [userData]) {
if(err) return console.log(err);
//console.log('userData', userData);
const token = jwt.sign({
data: {userId: userid},
}, SECRET);
res.render("index.hbs", {
appdata: {token, room, user: userData},
final scripts,
});
});
});
And here is my point, but I can't reach it:
app.post('/writeVideo', (req, res) => {
req.video.mv('test.wav', (err) => {
if (err) {
res.send(err);
} else {
res.send({
success: 'file write'
})
}
});
})
And here I am trying to knock on the point:
fetch('/writeVideo', {
method: 'POST',
credentials: "same-origin",
headers: {
'Content-type': 'application/json',
},
body: {
user: {
userId: 8
},
video: audioBlob
}
}).then(data => data.json()).then(data => console.log(data));
I read a little, they advise just using credentials: 'same-origin' || 'include', however it didn't work for me, I tried setting Cookie headers: 'JWT_TOKEN=token' in different ways - didn't work. Please tell me how should I proceed.
Thank you.

Related

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.

Problem structuring two factor authentication

const login = (req, res) => {
// console.log(req.body);
// let email = req.body.email.toLowerCase();
sequelize.models.User.findOne({
where: {
email: req.body.email,
},
})
.then(async (user) => {
if (!user) {
// console.log(" email not found is true");
return res.status(401).json({
success: false,
message: " Authentication failed, Wrong Credentials",
});
}
if (user.isActive == false) {
// console.log("user is not activated", user.isActive);
return res.status(400).json({
success: false,
message: "account is not activated",
});
}
console.log("test entry");
await user.comparePassword(req.body.password, async (err, isMatch) => {
console.log(req.body.password);
if (isMatch && !err) {
console.log("user crap");
// role_id: user.role_id,
const payload = {
user_id: user.user_id,
};
const options = {
expiresIn: "10day",
};
const token = await jwt.sign(payload, process.env.SECRET, options);
console.log("sssssss", payload);
if (user.twoFactorAuth == false) {
return res.json({
success: true,
token,
});
} else {
// let mobile = user.phone;
await twoFactorAuth(user); // we call the 2fa that will send a otp to the users cellphone
// console.log("after cb");
}
} else {
return res.json({
success: false,
msg: "Authentication failed.",
});
}
});
// console.log("user crap", user.user_id);
})
.catch((error) => {
return res.status(400).send(error);
});
};
const twoFactorAuth = async (user) => {
var data = qs.stringify({
sender: "hehe",
mobile: user.phone,
channel: "sms",
});
var config = {
method: "POST",
url: "https://blablabla",
headers: {
Authorization: "Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
},
data: data,
};
axios(config)
.then( async function (response) {
console.log(JSON.stringify(response.data));
// await verifyTwoFactorAuth (realToken)
})
.catch(function (error) {
console.log(error);
});
};
const verifyTwoFactorAuth = async(req, res) => {
//console.log("tet",req);
let otpcode = req.body.otpcode;
let mobile = req.body.mobile;
var data = qs.stringify({ mobile: mobile, code: otpcode });
var config = {
method: "POST",
url: "https://blablabla",
headers: {
Authorization: "Bearer xxxxxxxxxxxxxxxxxxxxxxxx",
},
data: data,
};
axios(config)
.then(async function (response) {
console.log(JSON.stringify(response.data));
if (response.data.code == 63 || response.data.status == 200) {
return res.json({
success: true,
token,
});
} else if (response.data.code == 21 || response.data.status == 422) {
return res.status(400).json({
success: false,
message: "wrong code, check your sms again",
});
}
})
.catch(function (error) {
console.log(error);
});
};
Hello, I am looking for a structure solution to how I should implement what I want.
Scenario: user try to login, system checks for username and passoword and generates the TOKEN, system finds that 2fa is active in users settings, system sends OTP to users cellphone.
Now my struggle begins, I am not sure what to do next, I thought about storing the token in users fields as tempToken then i look for the user via users mobile and extract the token that way, but I dont believe that this is best practice.
Any ideas of how to tackle this would be appreciated ! thank you

ERR_HTTP_HEADERS_SENT in Nodejs Server (AWS)

I'm asking again with this code provided Please Help Thank you. I am calling this API with Firebase function from Android using okhttp3, here the code below. I already subscribed to a plan in firebase to call external API
Firebase Cloud Function Code
exports.CustomerProfile = functions.https.onRequest((req, res) => {
const options = {
method: "POST",
uri: "http://3.xxxx.xx.xx2:3000/api/customers/profile",
formData: {
session_token: req.body.session_token
},
headers: {
"content-type": "application/x-www-form-urlencoded",
"x-auth-token": "xxxxxxE"
},
resolveWithFullResponse: true,
json: true,
simple: false
};
rp(options)
.then(function(response) {
res.send(response.body);
})
.catch(function(err) {
res.send(err);
});
});
API CODE
router.post("/profile", async (req, res) =>{
const customers = new Customers();
var data = req.body;
var token = req.body.session_token;
customers.findBySessionToken(token, (err, result) => {
if (!err) {
if(result[0].provider === 'gmail'){
var gmail = result[0].access;
customers.findByGmail(gmail, (err, result) => {
res.status(200).send(result);
});
}else if(result[0].provider === 'facebook') {
var facebook = result[0].access;
customers.findByFb(facebook, (err, result) => {
res.status(200).send(result);
});
}else if(result[0].provider === 'mobile') {
var mobile = result[0].access;
customers.findByMobile(mobile, (err, result) => {
res.status(200).send(result);
});
}
} else {
if (err.code === "ER_SIGNAL_EXCEPTION") {
res.status(400).send([{ message: err.sqlMessage }]);
} else {
res.status(400).send(err);
}
}
});
});
this means that you have already sent a response res.send... somewhere else , you cant do more than one response for a request.

How to send Refresh Token for new Access Token to Microsoft Graph (Passport-Azure-AD OIDCStrategy)

I'm having trouble understanding how to send back a refresh token to get a new access token.
I've looked at this documentation: https://developer.microsoft.com/en-us/graph/docs/concepts/nodejs and I basically need help with Authenticate User- step4 but they don't seem to go into more details.
I tried using passport-oauth2-refresh but I think because I'm using Azure AD, I kept getting Error: Cannot register: not an OAuth2 strategy. So I've decided to try to manually check the expiry instead.
I am able to retrieve a refresh token (POST /token with req.user.refreshToken) along with my access token and I store it in json but I don't know how to send it back.
Here is my index.js:
const express = require('express');
const router = express.Router();
const graphHelper = require('../utils/graphHelper.js');
const passport = require('passport');
const request = require('request');
const SERVER = process.env.SERVER;
let user_id = null;
router.get('/', (req, res) => {
if (!req.isAuthenticated()) {
res.render('login');
} else {
renderBotPage(req, res);
}
});
router.get('/login',
passport.authenticate('azuread-openidconnect', {failureRedirect: '/'}),
(req, res) => {
res.redirect('/');
});
router.get('/token',
function (req, res, next) {
passport.authenticate('azuread-openidconnect',
{
response: res, // required
failureRedirect: '/'
}
)
},
function (req, res) {
const options = {
headers: {
'content-type' : 'application/json'
},
method: 'POST',
url: SERVER,
json: {
'accessToken': req.user.accessToken,
'refreshToken': req.user.refreshToken
}
};
request(options,
function (error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body)
}
}
);
console.log('We received a return from AzureAD get token.');
res.redirect('/');
});
router.post('/token',
function (req, res, next) {
passport.authenticate('azuread-openidconnect',
{
response: res, // required
failureRedirect: '/'
}
)(req, res, next);
},
function (req, res) {
console.log('res after first token function', res);
const options = {
headers: {
'content-type' : 'application/json'
},
method: 'POST',
url: SERVER,
json: {
'accessToken': req.user.accessToken,
'refreshToken': req.user.refreshToken
}
};
request(options,
function (error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body)
}
}
);
res.redirect('/');
});
function renderBotPage(req, res) {
graphHelper.getUserData(req.user.accessToken, (err, user) => {
if (!err) {
res.render('chatbotOn', {
display_name: user.body.displayName,
user_id:user.body.id
});
} else {
// Catch of Expired token error
if (hasAccessTokenExpired(err)) {
req.session.destroy(() => {
req.logOut();
res.clearCookie('graphNodeCookie');
res.status(200);
res.redirect('/');
});
}
renderError(err, res);
res.render('chatbotOn', {
display_name: "Random User"
});
}
});
}
router.get('/disconnect', (req, res) => {
req.session.destroy(() => {
req.logOut();
res.clearCookie('graphNodeCookie');
res.status(200);
res.redirect('/');
});
});
function hasAccessTokenExpired(e) {
let expired;
if (!e.innerError) {
expired = false;
} else {
expired = e.forbidden &&
e.message === 'InvalidAuthenticationToken' &&
e.response.error.message === "Le token d'accès a expiré.";
}
return expired;
}
function renderError(e, res) {
e.innerError = (e.response) ? e.response.text : '';
res.render('error', {
error: e
});
}
module.exports = router;
My app.js
const callback = (iss, sub, profile, accessToken, refreshToken, done) => {
done(null, {
profile,
accessToken,
refreshToken
});
};
passport.use(new OIDCStrategy(config.creds, callback));
And here is my graphHelper.js:
const request = require('superagent');
function getUserData(accessToken, callback) {
request
.get('https://graph.microsoft.com/beta/me')
.set('Authorization', 'Bearer ' + accessToken)
.end((err, res) => {
callback(err, res);
});
}
exports.getUserData = getUserData;
here is my config.js:
module.exports = {
creds: {
redirectUrl: 'http://localhost:3000/token',
clientID: 'xxxxx', // regular
clientSecret: 'xxxxx', // regular
identityMetadata:
'xxxxxx',
allowHttpForRedirectUrl: true, // For development only
responseType: 'code id_token',
validateIssuer: false, // For development only
responseMode: 'form_post',
scope: ['openid', 'offline_access', 'Contacts.Read',
'Calendars.ReadWrite'
]
},
};

How to set headers in api call om nodeJs?

I am working on authentication in nodeJs. I have created successfully login API and it works well on the postman. I'm stuck on client side. It does not set token on headers. I am using the passport, jwt for authentication.
My code is:
app.post('/login', (req, res, next) => {
var name = {
name: req.body.name,
password: req.body.password
}
// let m = '';
// console.log(name)
request({
url: "http://localhost:3000/api/login",
method: "POST",
json: true, // <--Very important!!!
body: name
}, function (error, response) {
if (response.body.error == true) {
req.flash('errorMsg', response.body.message);
res.redirect('/');
}
else {
// localStorage.setItem('token', response.body.token);
// console.log(localStorage.getItem('token'))
// req.headers['authorization'] = response.body.token;
// res.setHeader('authorization', response.body.token);
// req.session['token'] = response.body.token;
// console.log(req.session['token'])
// res.set({
// 'Content-Type': 'text/plain',
// 'authorization':response.body.token
// });
// res.setHeader('authorization', response.body.token);
// req.headers['authorization'] = response.body.token;
res.redirect('/secret');
next();
}
});
// console.log(m);
});
and my middleware is:
app.use((req, res, next) => {
var token = req.body.token || req.session['token'] || req.query.token || req.headers['x-access-token'] || localStorage.getItem('token');
req.headers['authorization'] = token;
console.log(req.session['token'], token)
console.log(req.headers['authorization'], config.jwtSecret);
if (token) {
jwt.verify(token, config.jwtSecret, (err, decoded) => {
if (err) {
res.json({
'message': 'Failed to authenticate user'
});
} else {
req.decoded = decoded;
next();
}
});
} else {
// logger.warn('Unauthorized');
return res.sendStatus(401);
}
console.log(req.headers['authorization'])
});
I have tried all possible to set the token in headers but it didn't work well. If I get my token on app.use middleware then I can verify token easily but it didn't allow to set my token.
How can I do this??
Best way!
router.get('/your-route', async (req, res) => {
//...
res.setHeader('your-key', 'your-value');
//..
})
You can see output in header tab in browser or postman
your-key: your-value

Resources