Getting data in an Angular Component (Profile page) - javascript

I'm working on a MEAN Stack application. I have made authentication and authorization using jWt and it works like a charm.
The problem that I'm facing is how to get the user data in the Profile page component. I'm thinking about several options:
First, sending the email from the Login component to the Dashboard and then pass it to Profile. It will be easy from then to send a get request to get the user with the email.
Second, I don't know if it possible but I'm thinking of using the jwt I'm returning to the user to get his data since I created it with the provided email in Login
This is how I created the jwt token:
login: async (data, model) => {
try {
/**
* Fetch the admin from the Database
*/
const adminData = await baseRepository.findOne({ email: data.email }, model);
/**
* Check if an admin with that email exists
*/
if (!adminData) {
return (400, { message: "ADMIN NOT FOUND" })
} else {
/**
* Compare the input password with the hashed password in the database
*/
const admin = { email: adminData.email }
if (await bcrypt.compare(data.password, adminData.password)) {
/**
* Create a jwt Token and send it back to the client
*/
const accessToken = jwt.sign(admin, process.env.ACCESS_TOKEN_SECRET)
return ({ status: 200, accessToken: accessToken })
}
return ({ status: 401, accessToken: null })
}
}
catch (err) {
throw err
}
}
That's the method from the repository that I'm using to handle the request in the controller this way:
login: async (req, res) => {
try {
console.log("yo")
const { status, accessToken } = await authRepository.login(req.body, Admin)
if (status == 400) {
res.status(400).json({ message: "ADMIN NOT FOUND" })
} else if (status == 401) {
res.status(401).json({ message: "WRONG PASSWORD" })
}
res.status(200).json({ accessToken: accessToken })
}
catch (e) {
res.status(400).send({ error: e })
}
}
And these are the libraries I'm using:
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");

The response of the login service need to be the profile info

Related

My Login System in Node.js is not working

I'm using Node.js and MySQL for a login system. My problem is, login system is not working when I use async-await and promises. It's not giving errors but page keeps reloading and user cannot enter the system. What can the problem be? Is there a problem in my await declarations. I'm kind of new at fullstack programming. Thanks for your help.
At the top of the login controller, there is a async arrow function and below its code block, there are multiple awaits which are defined for some database calls and bcrypting password.
Should I return the database connection as .promise()
or not a promise? Sometimes code is working and user can enter, but sometimes cannot.
This Code Block For User Login
exports.login = async (req, res) => {
try {
const { email, password } = req.body;
// if (!email || !password) {
// return res.status(400).render("giriş_yap", {
// msg: "Lütfen e-mail veya şifrenizi giriniz",
// msg_type: "error",
// });
// }
const allDB = await login_db.query(`select * from users where email='${email}'`);
const user = allDB[0] ;
//console.log(user[0]) ;
if (user.length <= 0) {
return res.status(401).render("giriş_yap", {
msg: "Sistemde kaydınız bulunamadı",
msg_type: "error",
});
} else {
const passwordMatch = (await bcrypt.compare(password, user[0].PASS))
if (!passwordMatch) {
return res.status(401).render("giriş_yap", {
msg: "Emailiniz veya Şifreniz hatalı",
msg_type: "error",
});
} else {
const id = user[0].ID;
const token =jwt.sign({ id: id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN,
});
//console.log("The Token is " + token);
const cookieOptions = {
expires: new Date(
Date.now() +
process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000
),
httpOnly: true,
};
res.cookie("joes", token, cookieOptions);
res.status(200).redirect("/anasayfa");
}
}
} catch (error) {
console.log(error);
}
};
This Code Block for mysql database connection
const mySql = require("mysql2");
const config = require("../config_db");
const login_db = mySql.createConnection(config.db_login);
login_db.connect(function (err) {
if (err) {
console.log(err);
}
console.log("Kullanici bilgileri veritabanina başariyla baglandiniz.");
});
module.exports = login_db.promise();
Are you sure you didn't forget in your front-end this code ?
e.preventDefault()
If not, please share the front-end code also.
Also in your code, be careful with your console.log in the catch block on your login function. It can throw to infinite api call.

Unable to verify emails with JWT, need to find user with email but can't send email in the email

I am trying to verify user emails with JWT. My current set up is that a JWT is sent to a user when they try to log in if they do not have a confirmed email.
When the email is sent it composes a URL with the token and then sends the request to the server to verify the email. It worked great in postman as I could easily add the email that I want to verify in the body. But I can't think of a way how to do it in the browser.
This is the code that should verify the email.
confirmEmail = async (req, res, next) => {
const { email } = req.body
const param = req.params.token
const user = await userModel.findOne({email})
if(!user)
{
throw new HttpException(401, 'User not found')
}
if(user.confirmed)
{
throw new HttpException(401, 'User already confirmed')
}
if(!user.confirmed)
{
const confirmJWT = jwt.verify(param, process.env.SECRET_JWT)
if(!confirmJWT)
{
throw new HttpException(200, 'Token invalid')
}
const result = await userModel.emailConfirmed(email)
}
res.send('Database updated.')
}
This is the code that generates the JWT and sends it in an email.
if(!user.confirmed)
{
const emailToken = jwt.sign(
{
email: user.email
},
process.env.SECRET_JWT,
{
expiresIn: '15m'
}
)
console.log(emailToken)
emailModel.verifyEmail(email, emailToken)
throw new HttpException(401, 'Email not confirmed')
}
I was wondering if there is any way I can use the just the token to find the email of the user or is that not possible with JWT?
export const verifyEmail = () => {
try
{
return API()
.post(`/api/confirm/:token`, {}, {
params: {
token: store.user.authToken
},
email: store.user.email
})
.then(({data: userData}) => {
console.log('worked')
})
}
catch(error)
{
console.log(error)
}
}
import { verifyEmail } from '../../services/authAPI'
import { useUserStore } from '../../stores/user'
const store = useUserStore()
export default {
data()
{
return {
email: store.user.email
}
},
methods: {
async handleSubmit()
{
try
{
const response = await verifyEmail(this.email)
}
catch(err)
{
console.log(err)
}
}
}
}
</script>
Basically you do not need to send the email in the body as already encoded the email into the JWT. Once you do const verifiedToken = jwt.sign(token, secret key) You can do verifiedToken.email to grab the email.

How to handle 401 error status code error in Node.js/Express?

I am working on login functionality in my project, now, flow looks like this (from front-end to back-end):
async login() {
await login({
password: this.userPassword,
login: this.userLogin,
twoFactor: this.twoFactor
}).then((res) => {
if (res.error) {
//
} else {
console.log(res)
}
})
}
And here is starts problems, as you can see if something goes wrong, I return status code 401 and some error message. When I login with correct data, there is no problem with getting token, but when I provide wrong data I have external pending login endpoint in development tools in browser and then, after some time, Error: Request failed with status code 401 in front end terminal. Without this status(401) with just JSON it works fine, but when I try to add 401 code, application crashes.
const userService = require('./../services/userService')
const crypto = require('./../services/cryptoService')
const jwt = require('./../services/jwtService')
const twoFactorService = require('node-2fa')
module.exports = {
login: async (req, res) => {
let { login, password, twoFactor } = req.body
password = crypto.encrypt(password, process.env.APP_KEY)
const result = await userService.getUserToLogin(login, password)
if (!result) {
res.status(401).json({
error: 'Unauthorized'
})
} else {
const faCode = result.twofatoken
const result2F = twoFactorService.verifyToken(faCode, twoFactor);
if ( !result2F || result2F.delta !== 0 ) {
res.status(401).json({
error: 'Unauthorized'
})
} else {
const userId = crypto.encrypt(result.id, process.env.CRYPTO_KEY)
const token = await jwt.sign({
uxd: userId,
});
res.json(token);
}
}
}
}
Actually, I have no idea on what to do with that and how to handle this error.
Ok, here is the answer. Actually, you just need to handle this error in your router:
router.post('/login', async (req, res) => {
try {
const data = await api.post('/login', req.body)
res.json(data.data)
} catch (e) {
// Probably you have here just console.log(e), but this way, you can handle it
res.status(e.response.status).json(e.response.data)
}
})

how to fetch reset password api in front-end Node js

I'm student in web development. Currently, I'm trying to build a basic project, where I'm stack in implementing reset password feature, I really need help in how fetching reset password API in front-end using Axios. In short, the reset password API that I implemented works fine on Postman, but whenever I tried to pass in front-end and fetch the API in order to enable users to enter their new password and passwordValidation I kinda lost, below I share my code snippets:
backend code reset password
resetPassword = async(req, res) => {
try {
// Step 1: Get user based on the token
const validateHashedToken = crypto
.createHash('sha256')
.update(req.params.token)
.digest('hex');
const user = await User.findOne(
{
passwordResetToken: validateHashedToken,
passwordResetExpires: { $gt: Date.now() }
});
user.password = req.body.password;
user.passwordValidation = req.body.passwordValidation;
user.passwordResetToken = undefined;
user.passwordResetExpires = undefined;
await user.save();
// Step 3: Update the "passwordChangedAt" date
// Step 4: Log the user in and send a JWT
genResJWT(user, 200, res);
} catch (error) {
console.log('error', error)
}
};
Routes:
router
.route('/api/v1/users/resetpassword/:token')
.get(viewsController.getResetPasswordUrl)
.patch(viewsController.resetpassword);
controllers
exports.getResetPasswordUrl = async(req, res) => {
try {
const { token } = req.params.token;
const validToken = await User.findOne(
{
passwordResetToken: token
}
);
res.status(200).render('resetPassword',
{
title: 'resetpassword',
token: validToken
});
} catch (error) {
console.log(error);
}
};
exports.resetpassword = (req, res) => {
// I'm stack here and I really need help
res.status(200).render('profile', {
title: 'reset password successfuly'
});
};
front-end fetching api code:
import axios from 'axios';
export const resetPassword = async (password, passwordValidation) => {
try {
const res = await axios({
method: 'PATCH',
url:
`http://127.0.0.1:3000/api/v1/users/resetpassword/:token`,
data: {
password,
passwordValidation
}
});
if (res.data.status === 'success') {
window.setTimeout(() => {
location.replace('/me');
}, 500);
}
} catch (error) {
console.log('error', error.response.data.message);
}
};
On the front end, you are making a request to http://127.0.0.1:3000/api/v1/users/resetpassword/:token. Since token is a route parameter, you are directly passing in the string ":token" and not the actual value of the token.
Try this instead:
const res = await axios({
method: 'PATCH',
url:
`http://127.0.0.1:3000/api/v1/users/resetpassword/${token}`,
data: {
password,
passwordValidation
}
});
where token is a variable you need to define.
Assuming that you are using express, here is some documentation about parameter routing: https://expressjs.com/en/guide/routing.html#route-parameters
I fixed my issue with the following steps:
1- Use only GET request in my '/resetpassword/:token' route and submit the PATCH request with Axios.
2- Pass the 'token' along with the 'password' and the 'passwordValidation' as input data in the PATCH request.
3- create a hidden input within the 'resetPassword' form in order to submit the 'token' with the password and the 'passwordValidation' whenever users confirm their updated password.
Below is my code snippet in order to explain how goes the solution:
Routes:
router.get(
'/resetpassword/:token',
viewsController.resetPassword
)
controllers
exports.resetPassword = (req, res) => {
const token = req.params.token;
res.status(200).render('/login', {
title: 'reset password successfuly', { token }
});
};
front-end fetching API code:
import axios from 'axios';
export const resetPassword = async (password, passwordValidation, token) => {
try {
const res = await axios({
method: 'PATCH',
url:
`/api/v1/users/resetpassword/${token}`,
data: {
password,
passwordValidation
}
});
if (res.data.status === 'success') {
window.setTimeout(() => {
location.assign('/login');
}, 1000);
}
} catch (error) {
console.log('error', error.response.data.message);
}
};
the resetPassword form:
extends goaheadtravel
block content
main.main
.resetpassword-form
h2.heading-secondary.ma-bt-lg Please enter a new password and validate it
form.form.resetpassword--form
.form__group.ma-bt-md
label.form__label(for='password') Password
input#password.form__input(type='password' placeholder='••••••••' required='' minlength='8')
.form__group.ma-bt-md
label.form__label(for='passwordValidation') Confirm password
input#passwordValidation.form__input(type='password' placeholder='••••••••' required='' minlength='8')
input#resetToken(type='hidden' value=`${token}`)
.form__group.right
button.btn.btn--green Confirm new password
Hope that my solution will help other developers!

Forgot password functionality using NodeJs/Knex/Nodemailer and it is not working properly

Note: this is my first time posting, if you have feedback please let me know
Goal: I am building some endpoints that let a user reset their password if they forgot it. Flow would look like this:
User doesn't know password so they click on forgot password.
User types in email and clicks send
User receives email with link to reset password. Clicks on link and is redirected to type in their new password.
They click 'save' and they are redirected to login to sign in with their new password
I am using Insomnia to hit the endpoints for testing.
Things that are working:
When providing an email to reset password, Nodemailer does send out an email.
When updating the password it does show 'password updated' and gives a 200 status.
Bugs:
After trying to log in with that new password, it is not saving to the database. Only the old password will allow you to log back in.
Things I have tried:
I tried changing my user.model to use my findByEmail function and ran into some weird bugs, which then led me down a rabbit hold of issues.
I tried console logging quite a few things to see if I could trace the path.
I tried changing the user.update function but was not able to get it to work.
Here is my code:
Any guidance would be appreciated. If you need to look at any other files please let me know.
Forgot.password.js
const router = require('express').Router();
const crypto = require('crypto')
const User = require('../models/users.model')
const nodemailer = require('nodemailer')
router.post('/forgotpassword', (req, res) => {
let {
email
} = req.body
console.log(req.body)
// if (req.body.email === '') {
// res.status(400).json({ message: 'Email is required'})
// } console.error(req.body.email)
User.findBy({
email
})
.first()
.then(user => {
if (user === null) {
res.status(403).json({
message: 'Email not in db'
})
} else {
const token = crypto.randomBytes(20).toString('hex')
User.update({
resetPasswordToken: token,
resetPasswordExpires: Date.now() + 3600000,
})
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: `${process.env.EMAIL_USER}`,
pass: `${process.env.EMAIL_PASS}`
}
})
const mailOptions = {
from: `${process.env.EMAIL_USER}`,
to: `${user.email}`,
subject: '[Promoquo] Reset Password Link',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process within one hour of receiving it:\n\n' +
`http://localhost:5000/reset/${token}\n\n` +
'If you did not request this, please ignore this email and your password will remain unchanged.\n',
}
transporter.sendMail(mailOptions, (err, res) => {
if (err) {
console.log('ERROR coming from forgot.password js and it sucks', err)
} else {
console.log('here is the res', res)
res.status(200).json({
message: 'recovery email sent hell yes'
})
}
})
}
res.status(200).json({
message: 'Reset password email has been sent WOOHOO 🎉'
})
})
.catch(error => {
res.status(500).json({
message: 'ERROR on last catch forgotpassword.js, likely no user exists',
error
})
console.log(error)
})
})
module.exports = router
Update.password.js
const router = require('express').Router();
const passport = require('passport')
const bcrypt = require('bcrypt')
const User = require('../models/users.model')
const BCRYPT_SALT_ROUNDS = 12
router.put('/updatePasswordViaEmail', (req, res) => {
User.find({
where: {
username: req.body.username,
resetPasswordToken: req.body.resetPasswordToken,
resetPasswordExpires: Date.now() + 3600000,
}
})
.then(user => {
if (user == null) {
console.error('password reset link has expired')
res.status(403).json({ message: 'Password reset link is invalid or has expired' })
} else if (user != null) {
console.log('user exists in db')
bcrypt.hash(req.body.password, BCRYPT_SALT_ROUNDS)
.then(hashedPassword => {
User.update({
password: hashedPassword,
resetPasswordToken: null,
resetPasswordExpires: null,
})
})
.then(() => {
console.log('log for THEN updating password')
res.status(200).json({ message: 'password updated' })
})
} else {
console.error('no user exists in db to update')
res.status(401).json({ message: 'no user exists in db to update'})
}
})
})
module.exports = router
Users.model.js
const db = require('../dbConfig')
module.exports = {
add,
find,
findBy,
findById,
findByEmail,
findByType,
update
};
function find() {
return db('users').select('id', 'username', 'email', 'password');
}
function findBy(filter) {
return db('users').where(filter);
}
async function add(user) {
const [id] = await db('users').insert(user);
return findById(id);
}
function findById(id) {
return db('users').where({ id }).first();
}
function findByEmail(email) {
return db('users').where({ email }).first();
}
function findByType(type) {
return db('users').where({ type }).first();
}
function update(changes, id) {
return db('users').where({ id }).update(changes)
}
20200913211559_users.js (this is the table)
exports.up = function(knex) {
return knex.schema.createTable('users', tbl => {
tbl.increments();
tbl.string('firstname', 30).notNullable();
tbl.string('lastname', 30).notNullable();
tbl.string('username', 30).notNullable()
tbl.string('email', 50).notNullable()
tbl.string('password', 128).notNullable();
tbl.string('type').notNullable();
tbl.boolean('confirmed').defaultTo('false');
tbl.string('resetPasswordToken');
tbl.date('resetPasswordExpires');
})
};
exports.down = function(knex) {
return knex.schema.dropTableIfExists('users')
};
Your User.update() lines aren't running (you either need to return their promises into the chains of promises, or hook into their callbacks). async/await is your friend here to avoid "callback hell."
const user = await User.find({
where: {
username: req.body.username,
resetPasswordToken: req.body.resetPasswordToken,
resetPasswordExpires: Date.now() + 3600000,
}
})
if (!user) { /* ... */ }
const token = crypto.randomBytes(20).toString('hex')
await User.update({ // await here!
resetPasswordToken: token,
resetPasswordExpires: Date.now() + 3600000,
})

Categories

Resources