Unable to get cookie authentication working with pouchdb - node.js

I'm having trouble getting pouchdb working on the client side. I've looked through several other Stack Overflow posts, but I still haven't been able to figure it out. I've also looked into pouchdb-authentication, but it doesn't seem to be the one I'm looking for.
Below is my Express backend.
I first get the password from the user and validate it before making a post request to /_sessions to get the token. I then return a string back to the client. The string looks like this:
AuthSession=dGVzdDo1RTRDMDlFNDoCqn-ogpyksRGBXe7x7DVinw075A; Version=1;
Expires=Tue, 18-Feb-2020 16:09:32 GMT; Max-Age=600; Path=/; HttpOnly
In the POST route for localhost:8080/session
bcrypt.compare(req.body.password, users[0].password, function (error, result) {
if (error) { res.status(400).json({ error }); }
if (result === true) {
// return a cookie auth token from couchdb
axios.post('http://localhost:5984/_session', {
name: req.body.username,
password: users[0].password
}).then((response) => {
const cToken = response.headers['set-cookie'][0];
return res.json(cToken); // send auth token back to client
}).catch((err) => {
return res.status(400).json(err);
});
});
};
However, the client side doesn't seem to recognize that I got a cookie token and I get this error:
{ error: "unauthorized", reason: "You are not authorized to access this
db.", name: "unauthorized", status: 401, message: "You are not
authorized to access this db." }
Here is my client side code:
axios.post('http://localhost:8080/session/', { username: this.form.username, password: this.form.password }).then((res) => {
console.log(res.data);
const db = new PouchDB('http://localhost:5984/somedb', { headers: { Cookie: res.data } });
db.info().then((info) => {
db.put({
_id: 'mydoc',
title: 'test'
}).then((response) => {
// handle response
}).catch((err) => {
console.log(err);
});
});
}).catch((error) => {
console.log(error);
});
Is it because I'm not getting the header/the cookie isn't being set? Can I not just pass the string when I create the pouchdb instance?
Any help or guidance would be appreciated. Thanks in advance.

Related

Cookie token sent by server but not stored in browser

I have this code in node js API :
const jwt = require("jsonwebtoken");
generateToken = (user, res) => {
const token = jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, {
expiresIn: "1800s",
});
res
.cookie("token", token, {
httpOnly: true,
})
.status(200)
.json({ message: "Logged in successfully 😊 👌" });
};
module.exports = generateToken;
I have this code in Next js project :
const onSubmitLogin = (data) => {
axios
.post(
`http://localhost:8000/login`,
{
email: data.email,
password: data.password,
},
{
headers: {
"Content-Type": "application/json; charset=UTF-8",
},
}
)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
};
If I use Postman, i get the cookie with the token.
But, when I use the browser I dont get the cookie stored in cookies.
I tried to add withCredentials: true, in axios request but nothing changes.
However, I get the message "Logged in successfully 😊 👌" in the browser's console

How to estabilish express session with passport.js trough multiple APIs

nodejs newbie here.
Currently i'm working on implementing local authentication via passport.js for admin user. I have the following setup: web client for admin, api for admin, and service api.
So the call for auth is goes like this:
clientAdmin > apiAdmin > serviceApi (auth) > apiAdmin > clientAdmin.
However, express-session is not working properly on this setup, its just doesen't store passport in session and never runs deserializeUser function. I assume that when serviceApi responds to apiAdmin, its trying to store a cookie in it, but apiAdmin can't store it.
What shall i do to get the cookie from response on apiAdmin side, and then pass it to the client? Or maybe i can kinda resend the response that i get from serviceApi to client?
P.S. If i do a call directly from client to service, ignoring adminApi, all works fine, so my middleware and passport config are configured properly. But i need to implement a setup with 2 apis.
Function on client that calls adminapi
const login = () => {
axios({
method: "POST",
data: {
username: username,
password: password,
},
withCredentials: true,
url: config.loginURL,
}).then((res) => {
if (res.data.userId) {
setUser({ id: res.data.userId });
}
});
};
Function on adminapi that calls serviceapi
loginHandler(req: express.Request, res: any) {
axios({
method: "POST",
data: req.body,
withCredentials: true,
url: config.loginURL,
})
.then((response) => {
res.send(response.data);
})
.catch((err) => console.error(err));
}
Function on serviceapi
loginHandler(req: any, res: any, next: express.NextFunction) {
passport.authenticate("local", (err, user) => {
if (err) throw err;
if (!user) res.json({ message: "Invalid credentials" });
else {
req.logIn(user, (err: Error) => {
if (err) throw err;
res.json({ message: "Authorized", userId: user.id });
});
}
})(req, res, next);
}

Password Reset Auth using MERN Stack

I'm implementing an auth token within the nodemailer email that is sent whenever a user resets their password. I've got the generated url with the appended token setup and sending properly, I just can't seem to get my routing right to handle the authentication of said token.
My request is returning a 404 saying my GET is not found (GET http://localhost:3000/reset/XXXXXXXXXXXX 404 (Not Found) ). Could anyone help point me in the right direction here?
Here's my api route for the server
router.get('/reset', (req, res, next) => {
User.findOne({ resetPasswordToken: req.query.resetPasswordToken }).then(user => {
if (user == null) {
res.json('Password link is invalid or has expired');
} else {
res.status(200).send({
username: user.email,
message: 'Password link accepted',
})
}
})
});
And my code to handle the request
componentDidMount() {
console.log(this.props.match.params.token);
axios.get('/reset' + this.props.match.params.token)
.then(response => {
// Conditional logic here based on response returned
})
.catch(function (error) {
console.log(error);
})
}
You need to tell express to expect the parameter in the url like this:
router.get('/reset/:token', (req, res, next) => {
// token is inside req.params.token
User.findOne({ resetPasswordToken: req.params.token }).then(user => {
if (user == null) {
res.json('Password link is invalid or has expired');
} else {
res.status(200).send({
username: user.email,
message: 'Password link accepted',
})
}
})
});
Then make sure there is a slash in the url when you make the request:
axios.get('/reset/' + this.props.match.params.token)
.then(response => {
// Conditional logic here based on response returned
})
.catch(function (error) {
console.log(error);
})

Node.js error when sending request from react (net::ERR_TOO_MANY_REDIRECTS )

After making request to the server, am getting net::ERR_TOO_MANY_REDIRECTS. This was working earlier, now the App cant make any request to the server.
Though the API's are working when tested with Postman.
This is the action that makes the request to the server
//Login User
export const login = (email, password) => async (dispatch) => {
const config = {
headers: {
"Content-Type": "application/json",
},
};
const body = JSON.stringify({ email, password });
console.log(email, password); //This is where the run time stops and catch error
try {
const res = await axios.post(authLogin, body, config);
console.log(res);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data,
});
dispatch(loadUser());
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, "danger")));
}
dispatch({
type: LOGIN_FAIL,
});
}
};
This is the controller for the API that's been called
// #route POST api/auth/login
// #desc Login user and return JWT token
// #access Public
const loginUser = async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user)
return res.status(401).json({
errors: [
{
msg:
"The email address " +
email +
" is not associated with any account. Double-check your email address and try again.",
},
],
});
//validate password
if (!user.comparePassword(password))
return res
.status(401)
.json({ errors: [{ msg: "Invalid email or password" }] });
// Make sure the user has been verified
if (!user.isVerified)
return res.status(401).json({
errors: [
{
type: "not-verified",
message: "Your account has not been verified.",
},
],
});
// Login successful, write token, and send back user
res.status(200).json({ token: user.generateJWT() });
} catch (error) {
console.error(error.message);
res
.status(500)
.json({ errors: [{ msg: "Server unavailable, try again latter" }] });
}
};
This is a react, node.js, mongoDB and Redux project. Have not experience this before.
Kindly help if you have any idea what i did wrong.
Thanks.
Resolved. It turns out that the SSL-VPN i was using on my machine caused the issue. All the APIs started working immediately i disconnected the VPN.

react & node API - fetch function error

I'm just new in React and NodeJS express programming and I'm stuck in some error for hours.
when I'm trying to fetch, sometimes I got a response (but not the my response)
and sometimes I got 'failed to fetch'.
I have tried to understand 'cors' concept without a lot of understanding,
but I have commit app.use(cors()) that allowed every source.
note that my server sometimes got 'OPTIONS' request, and sometimes getting 'POST' request.
in my React, I have this function:
fetch('http://localhost:3000/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify ({
user: this.state.username,
pass: this.state.password,
})
}).then(res => {
console.log(res.msg);
})
.catch(function(err) {
alert(err);
})
}
in my NodeJS I have this function:
router.post('/', (req, res) => {
let user = {
username: req.body.user,
password: req.body.pass
}
UserModel.findOne({'username': user.username, 'password' : user.password}, function(err, user) {
if (err) {
res.json({
ok: false,
msg: 'login failed, try later'
});
} else if (user) {
let token = jwt.encode(user, secret);
res.json({
msg: 'logged in',
ok: true
});
} else {
res.json({
ok: false,
msg: 'invalid input'
});
}
});
Im very confused, I hope you can help me.
Thanks.
You aren't accessing the JSON of the response correctly. You need to call the Body#json method of the response to actually access the JSON content. Also note that it returns a promise that resolves to the JSON content of a response:
fetch('…', { … })
.then(res => res.json())
.then(json => {
console.log(json.msg);
});
Also, I recommend sending an HTTP status code along with the JSON instead of having an ok property. That is a standard way and has builtin support through the Response object:
res.status(200).json({ … });

Resources