When page reloaded, the JWT token set the original - node.js

I tried to check JWT token worked actually or not. set in local storage. but after reloading, it set the original automatically. so here is any wrong or good suggestion?
front end:
in front end code is.
let userToken = localStorage.getItem("accessToken")
useEffect(() => {
axios.get(`http://localhost:5000/mycars/${user.uid}`,
{
headers: {
email: user.email,
token: userToken
}
})
.then(response => {
console.log(response);
if (response.data.success) {
setError("No car found")
}
else if (response.data.error) {
setError("Unauthorized access")
}
else {
setMycars(response.data)
setError("")
}
})
.catch(err => {
console.log("error is ", err);
})
}, [user.uid, user.email, userToken])
backend:
app.get('/mycars/:id', async (req, res) => {
const uid = req.params.id;
const getEmail = req.headers.email;
const accessToken = req.headers.token;
try {
const decoded = await jwt.verify(accessToken, process.env.DB_JWTTOKEN,
function (err, decoded) {
let email;
if (err) {
email = "invalid email"
}
if (decoded) {
email = decoded.email
}
return email;
});
// console.log(getEmail, decoded);
if (getEmail === decoded) {
const query = {}
const cursor = carCollection.find(query);
const cars = await cursor.toArray();
const mycars = await cars.filter(car => car.uid === uid)
if (mycars.length === 0) {
res.send({ success: "No car found" })
}
else {
res.send(mycars)
}
}
else {
res.send({ error: "Unauthorized access" })
}
}
catch (err) {
}
with the code , I wanted to check the JWT token manually changing in local storage. when page reloaded, the token execute new. and the edited not remaining

Related

Struggling to verify new users: Node JS

I am trying to implement a mechanism to allow new users to verify their account with a link sent to their email address.
Here's is my subscribe route in routes/user/index.js, which is working to send the email correctly:
require('dotenv').config();
const { v4 } = require('uuid');
const nodemailer = require('nodemailer');
const sibApiV3Sdk = require('sib-api-v3-sdk');
const express = require('express');
const stripe = require('../middlewares/stripe')
const db = require("../models");
const cors = require('cors');
const User = db.user;
const Feedback = db.feedback;
const defaultClient = sibApiV3Sdk.ApiClient.instance;
// Configure API key authorization: api-key
const apiKey = defaultClient.authentications['api-key'];
apiKey.apiKey = process.env.SENDINBLUE_API_KEY;
const transactionalEmailsApi = new sibApiV3Sdk.TransactionalEmailsApi();
// Configure nodemailer
const transporter = nodemailer.createTransport({
host: "smtp-relay.sendinblue.com",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: "noreply#redacted.ai",
pass: "redacted"
}
});
// Define generateVerificationToken function
function generateVerificationToken() {
return v4();
}
// Prepare Core Router
let app = express.Router()
app.post('/stripe/subscribe', async (req, res) => {
const domainURL = process.env.DOMAIN;
const { priceId, trial } = req.body
try {
let user = await User.findOne({ _id: req.user._id });
let customer = user.customerId ? { customer: user.customerId } : {customer_email: user.email};
const subscription_data = trial ? { trial_period_days: 7 } : {};
const session = await stripe.checkout.sessions.create({
mode: 'subscription',
payment_method_types: ['card'],
...customer,
line_items: [
{
price: priceId,
quantity: 1,
},
],
subscription_data,
success_url: `${domainURL}/index.html`,
cancel_url: `${domainURL}/signup/failed`,
});
let credits = 0;
if (priceId === process.env.STRIPE_PRODUCT_FREE) {
credits = 0;
} else if (priceId === process.env.STRIPE_PRODUCT_ENTRY) {
credits = 0;
} else if (priceId === process.env.STRIPE_PRODUCT_PRO) {
credits = 0;
}
// Check if user already has a verification_token
if (!user.verification_token) {
const token = generateVerificationToken();
console.log("generated token: ", token);
const updatedUser = await User.findOneAndUpdate({ _id: req.user._id },
{
credits: credits,
verification_token: token,
isVerified: false
},
{
new: true
});
console.log("updatedUser: ", updatedUser);
const verificationLink = `${domainURL}/verify?token=${updatedUser.verification_token}`;
const mailOptions = {
from: 'noreply#redacted.ai',
to: user.email,
subject: 'Verify your email address',
html: `Please click on the following link to verify your email address: ${verificationLink}`
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
} else {
console.log('User already has a verification token.');
}
const updateResult = await User.updateOne({_id: req.user._id}, {verification_token: user.verification_token}, {upsert: true});
console.log("updateResult: ", updateResult);
// Send verification email after stripe step completes
if (!user.isVerified) {
const verificationLink = `${domainURL}/verify?token=${user.verification_token}`;
const mailOptions = {
from: 'noreply#redacted.ai',
to: user.email,
subject: 'Verify your email address',
html: `Please click on the following link to verify your email address: ${verificationLink}`
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
}
// Redirect user to the verify route
res.redirect(303, session.url);
} catch (e) {
res.status(400);
return res.send({
error: {
message: e.message,
}
});
}
});
Immediately after this, I then have a verify route:
app.get('/verify', cors(), async (req, res) => {
const { token } = req.query;
try {
// Find user with matching token
let user = await User.findOne({ verification_token: token });
if (!user) {
throw new Error('Invalid token');
}
// Update user verification status
user.isVerified = true;
const savedUser = await user.save();
// Send verification email
if (savedUser.isVerified) {
const mailOptions = {
from: 'noreply#redacted.ai',
to: savedUser.email,
subject: 'Email Verified!',
html: `Your email has been verified! Welcome to redacted.ai`
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
}
// Redirect user to success page
res.redirect('/index.html#/verify/success');
} catch (e) {
res.status(400);
return res.send({
error: {
message: e.message,
}
});
}
});
I also have a file called src/verify.js to deal with things on the front-end:
import React, { useEffect, useState } from 'react';
import { useHistory } from 'react-router-dom';
function Verify(props) {
const [isVerified, setIsVerified] = useState(false);
const { token } = props.match.params;
const history = useHistory();
useEffect(() => {
// logic to process token and set isVerified to true/false
fetch(`/verify/${token}`)
.then(res => res.json())
.then(data => {
if (data.isVerified) {
setIsVerified(true);
}
});
}, [token]);
useEffect(() => {
// redirect to success page if isVerified is true
if (isVerified) {
history.push('/index.html#/verify/success');
}
}, [isVerified, history]);
return (
<div>
{isVerified ? (
<div>Your email has been verified! Welcome to redacted.ai</div>
) : (
<div>Invalid token.</div>
)}
</div>
);
}
export default Verify;
However, when the user clicks on the link in their email, the verify route does not initiate. Rather, nothing happens at all in the terminal except for profile refresh, and I'm not sure why.
As an aside, I can see in the database that the new user has a verification_token and isVerfied is set to false. That verification_token matches the one sent in the email.
I'm very new to Node JS so suspect I'm missing something obvious! Thanks so much in advance.
PS.
As a work around, I attempted to try a different approach, and created a form that the user could go to and copy and paste in their verification_token: the form looked like this:
import React, { useState } from 'react';
import TOOLS from './tools'
import config from './config'
import Header from './Header'
let baseURL = config.baseURL
const VerifyPage = () => {
const [verificationToken, setVerificationToken] = useState('');
const [error, setError] = useState('');
const [responseData, setResponseData] = useState({});
const handleSubmit = async (event) => {
event.preventDefault();
const token = window.localStorage.getItem('token');
console.log('Token: ', token);
console.log('Authorization header: ', `Bearer ${token}`);
// Make a request to your API to verify the token
try {
const response = await fetch(`${baseURL}user/verify`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ verificationToken })
});
console.log('Request URL: ', `${baseURL}user/verify`);
console.log('Request body: ', JSON.stringify({ verificationToken }));
const responseJson = await response.json();
setResponseData(responseJson);
console.log('Response status: ', response.status);
console.log('Response text: ', await response.text());
if (!response.ok) {
throw new Error(responseJson.message);
}
// Show a success message or redirect to another page
} catch (error) {
setError(error.message);
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="verificationToken">Verification Token:</label>
<input
type="text"
id="verificationToken"
value={verificationToken}
onChange={(event) => setVerificationToken(event.target.value)}
/>
</div>
{error && <p style={{ color: 'red' }}>{error}</p>}
<button type="submit">Verify</button>
{responseData && JSON.stringify(responseData)}
</form>
);
};
export default VerifyPage;
And with this in place, I altered my verify route to looks like this:
app.post("/verify", (req, res) =\> {
console.log('Received request to /verify');
const { token } = req.body;
console.log('Received verification token:', token);
User.findOne({ token }, (err, user) => {
if (err) {
console.error('Error finding user:', err);
return res.status(500).send({ error: "Error verifying account" });
}
if (!user) {
console.error('No user found with provided verification token');
return res.status(400).send({ error: "Invalid Token" });
}
user.isVerified = true;
user.verificationToken = undefined;
user.save((err) => {
if (err) {
console.error('Error saving user:', err);
return res.status(500).send({ error: "Error verifying account" });
}
console.log('User verified successfully');
return res.send({ message: "Account verified successfully" });
});
});
});`
But whenever the user attempted to put in their valid token, they would get something like this:
"Unexpected token 'F', "Forbidden" is not valid JSON"
Moreover, this is all that would show up in the terminal:
`"OPTIONS /api/user/verify 204 0.285 ms - 0 POST /api/user/verify 403 1.558 ms - 9" `
And, under the JWT code, this would show up in the console: "Failed to load resource: the server responded with a status of 403 (Forbidden)"
Truth be told, I'd be happy to get this working either via the form, or by having users click the link in the email. The latter is preferable - but either would work.

Decoding Firebase ID token failed. Make sure you passed the entire string JWT which represents an ID token

I didn't initially get this error, but it mysteriously appeared later on in my code. I tried following allong with the firebase documentation and using the auth.getAuth() method but then got the following error:
** : TypeError: auth.getAuth(...).verifyIdToken is not a function **
This is my auth code:
//const { auth } = require('firebase-admin');
const { admin, db } = require('./admin');
//1. ******************
//const auth = require('firebase/auth');
module.exports = (req, res, next) => {
let idToken;
if(req.headers.authorization && req.headers.authorization.startsWith('Bearer ')){
idToken = req.headers.authorization.split('Bearer')[1]
//returns an array of 2 strings --> 2nd element is the token
}
else{
console.error("NO TOKEN FOUND");
return res.status(403).json({error: "Unauthorized"});
}
admin.auth().verifyIdToken(idToken)
.then(decodedToken => {
req.user = decodedToken;
console.log(decodedToken);
return db.collection('users')
.where('userId', '==', req.user.uid)
.limit(1)
.get();
})
.then(data => {
req.user.handle = data.docs[0].data().handle;
return next();
})
.catch(err => {
console.error('Error while verifying token', err);
return res.status(403).json(err);
})
}
** where admin is require('firebase-admin');
I tried applying the auth.getAuth() method in the documentation, but my postman response says it is not a function. I'm very lost right now, any help would be very appreciated.
This is the full error:
{ "code": "auth/argument-error",
"message": "Decoding Firebase ID token failed. Make sure you passed the entire string JWT which represents an ID token. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token."
}
Here is my users.js that the id token gets to:
const { admin, db } = require("../util/admin");
const config = require('../util/config')
const firebase = require('firebase/app')
firebase.initializeApp(config)
const { validateSignUpData, validateLoginData, reduceUserDetails} = require('../util/validators')
const auth = require('firebase/auth');
// const { user } = require("firebase-functions/v1/auth");
exports.signup = (req,res) => {
const newUser = {
email:req.body.email,
password:req.body.password,
confirmPassword:req.body.confirmPassword,
handle:req.body.handle,
};
const { valid, errors } = validateSignUpData(newUser);
if(!valid) return res.status(400).json(errors);
//when a user signs up give them a blank image
const noImg = 'blankpic.png';
//declare an errors object as an empty object
let token, userId;
db.doc(`/users/${newUser.handle}`).get()
.then((doc) => {
if(doc.exists){
return res.status(400).json({ handle: 'this handle is already taken'})
} else{
return auth.createUserWithEmailAndPassword(auth.getAuth(), newUser.email,newUser.password)
}
})
.then((data) => {
//return access token for user to req more data
//return data.user.getIdToken();
userId = data.user.uid;
return data.user.getIdToken();
})
.then((idToken) => {
token = idToken;
//create user document
const userCredentials = {
handle: newUser.handle,
email: newUser.email,
createdAt: new Date().toISOString(),
imageUrl: `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${noImg}?alt=media`,
userId
};
//persist document into users cllection
return db.doc(`/users/${newUser.handle}`).set(userCredentials);
//return res.status(201).json( { token } );
})
.then(() => {
return res.status(201).json({ token })
})
.catch((err) => {
console.error(err);
if (err.code == 'auth/email-already-in-use') {
return res.status(400).json({ email: 'Email is already in use'})
}
return res.status(500).json({ general: "Something went wrong with server; please try again"});
});
}
exports.login = (req,res) => {
const user = {
email: req.body.email,
password: req.body.password
};
const { valid, errors } = validateLoginData(user);
if(!valid) return res.status(400).json(errors);
auth.signInWithEmailAndPassword(auth.getAuth(), user.email, user.password)
.then(data => {
return data.user.getIdToken();
})
.then(token => {
return res.json({ token });
})
.catch((err) => {
console.error(err);
return res
.status(403).json({general: 'Wrong credentials, please try again'});
});
}
exports.addUserDetails = (req,res) => {
let userDetails = reduceUserDetails(req.body);
db.doc(`/users/${req.user.handle}`).update(userDetails)
.then(() => {
return res.json({ message: 'Details add successfully'});
})
.catch(err => {
console.error(err);
return res.status(500).json({error: err.code});
})
}
exports.getAuthenticatedUser = (req,res) => {
let userData = {};
db.doc(`/users/${req.user.handle}`).get()
.then(doc => {
if(doc.exists){
userData.credentials = doc.data();
return db.collection('likes').where('userHandle', '==', req.user.handle).get()
}
})
.then(data => {
userData.likes = [];
data.forEach(doc => {
userData.likes.push(doc.data());
});
//return res.json(userData);
return db.collection('notifications').where('recipient', '=='. req.user.handle).get();
// .orderBy('createdAt').limit(10).get();
})
.then(data => {
userData.notifications = [];
data.forEach(doc => {
userData.notifications.push({
//recipient: doc.data().recipient,
sender: doc.data().sender,
createdAt: doc.data().createdAt,
screamId: doc.data().screamId,
type: doc.data().type,
read: doc.data().read,
notificationId: doc.id
});
});
return res.json(userData);
})
.catch(err => {
console.error(err);
return res.status(500).json({ error: err.code });
})
}
exports.getUserDetails = (req, res) => {
let userData = {};
db.doc(`/users/${req.params.handle}`)
.get()
.then((doc) => {
if (doc.exists) {
userData.user = doc.data();
return db
.collection("critech")
.where("userHandle", "==", req.params.handle)
//.orderBy("createdAt", "desc")
.get();
} else {
return res.status(404).json({ errror: "User not found" });
}
})
.then((data) => {
userData.posts = [];
data.forEach((doc) => {
userData.posts.push({
body: doc.data().body,
createdAt: doc.data().createdAt,
userHandle: doc.data().userHandle,
userImage: doc.data().userImage,
likeCount: doc.data().likeCount,
commentCount: doc.data().commentCount,
screamId: doc.id,
});
});
return res.json(userData);
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
};
exports.uploadImage = (req, res) => {
const busboyCons = require("busboy");
const path = require("path");
const os = require("os");
const fs = require("fs");
var busboy = busboyCons({ headers: req.headers });
let imageToBeUploaded = {};
let imageFileName;
// String for image token
//let generatedToken = uuid();
busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
console.log(fieldname, filename, mimetype);
// if (mimetype !== "image/jpeg" && mimetype !== "image/png") {
// return res.status(400).json({ error: "Wrong file type submitted" });
// }
// my.image.png => ['my', 'image', 'png']
filename = filename.toString();
const imageExtension = filename.split(".")[filename.split(".").length - 1];
// 32756238461724837.png
imageFileName = `${Math.round(
Math.random() * 1000000000000
).toString()}.${imageExtension}`;
//tmdir() --> temporarydirectory
const filepath = path.join(os.tmpdir(), imageFileName);
imageToBeUploaded = { filepath, mimetype };
//use file system lib to create the file object using the node js function file.pipe
file.pipe(fs.createWriteStream(filepath));
});
busboy.on("finish", () => {
admin
.storage()
.bucket()
.upload(imageToBeUploaded.filepath, {
resumable: false,
metadata: {
metadata: {
contentType: imageToBeUploaded.mimetype,
//Generate token to be appended to imageUrl
// firebaseStorageDownloadTokens: generatedToken,
},
},
})
.then(() => {
//construct image url to add to our user
// Append token to url
const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}`;
return db.doc(`/users/${req.user.handle}`).update({ imageUrl });
})
.then(() => {
return res.json({ message: "image uploaded successfully" });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: "something went wrong" });
});
});
busboy.end(req.rawBody);
};
exports.markNotificationsRead = (req, res) => {
let batch = db.batch();
req.body.forEach((notificationId) => {
const notification = db.doc(`/notifications/${notificationId}`);
batch.update(notification, { read: true });
});
batch
.commit()
.then(() => {
return res.json({ message: "Notifications marked read" });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
};
This is the token I get back when I log in 2
The response I get back when I use the token in my authorization header in Postman 1
The authorization header is of format Bearer <Token> with a space in between. However you are passing 'Bearer' in split() which would result in ['', ' <token>'] (notice the additional whitespace before actual token). You must use .split(" ") and this should resolve it. Try refactoring the code as shown below:
if( req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
idToken = req.headers.authorization.split(' ')[1]
}
const r1 = "Bearer token".split("Bearer")
const r2 = "Bearer token".split(" ")
console.log(`Token 1: '${r1[1]}'`)
console.log(`Token 2: '${r2[1]}'`)

Data Type Error when create a new user Knex Postgresql Node.js

I have this createUser method:
const createUser = (request, response) => {
const { username, password, score } = request.body
database("user")
.select()
.where({ username })
.first()
.then(user => {
if (!user) {
return bcrypt.hash(password, 12)
.then(hashedPassword => {
return database("user").insert({
username, password_digest: hashedPassword, score
}).returning("*")
})
.then(users => {
const secret = "HERESYOURTOKEN"
jwt.sign(users[0], secret, (error, token) => {
console.log(users[0])
response.json({ token, user: users[0] })
})
})
}
response.send("Please choose another username")
}).catch(error => {
response.status(401).json({
error: error.message
})
})
}
And this Authentication method:
function authenticate(request, response, next){
const token = request.headers.authorization.split(" ")[1]
const secret = "HERESYOURTOKEN";
if (!token) {
response.sendStatus(401)
}
let id = null
try {
id = jwt.verify(token, secret)
} catch(error){
response.sendStatus(403)
}
const user = database("user")
.select()
.where("id", id)
.first()
request.user = user;
next();
}
And when I use the Postman to create a new user it gives me 401 Unauthorized error with message:
enter image description here
The score data type is integer:
exports.up = function(knex) {
return knex.schema.createTable("user", table => {
table.increments()
table.string("username")
table.string("password_digest")
table.integer("score")
})
};
exports.down = function(knex) {
return knex.schema.dropTableIfExists("user")
};
Probably someone can help me with it.
The error should be from jwt.sign() where your secret is not in a right format.
Can you try a simple const secret = "ABC" to see if it works?

Problem with auth in Firebase - why are my tokens instantly expiring?

I'm testing out a route in a firebase app I'm building. The route in question recieves 'shouts' which are akin to status updates. Anyway, I just integrated auth to protect this route using FBuath, but I keep getting the following error:
Firebase ID token has expired. Get a fresh ID token from your client app and try again
I've tried relogging in using valid credentials, and then instantly trying to post something via the route, but keep getting this error. Any thoughts as to why? Code as follows, and the route in question has the endpoint '/shout'. Cheers
const functions = require('firebase-functions');
const admin = require('firebase-admin')
admin.initializeApp()
const config = {
apiKey: "AIzaSyBZjz9BNwj4UDwWLoQ1SOD5hB5QcNw3qqs",
authDomain: "social-ape-21874.firebaseapp.com",
databaseURL: "https://social-ape-21874.firebaseio.com",
projectId: "social-ape-21874",
storageBucket: "social-ape-21874.appspot.com",
messagingSenderId: "323044904203",
appId: "1:323044904203:web:edcbc619169a2087f8e60e",
measurementId: "G-T34PXDM1X7"
}
admin.initializeApp
const express = require('express')
const app = express()
const firebase = require('firebase')
firebase.initializeApp(config)
const db = admin.firestore()
app.get('/shouts', (req,res) => {
db
.collection('shouts')
.orderBy('createdAt', 'desc') //returns shouts in order in which they were made
.get()
.then((data) => {
let shouts = []
data.forEach((doc) => {
shouts.push({
shoutId: doc.id,
body: doc.data().body,
userHandle: doc.data().userHandle,
createdAt: doc.data().createdAt
})
})
return res.json(shouts)
})
.catch((err) => console.error(err))
})
const FBauth = (req,res,next) => {
let idToken
if(req.headers.authorization && req.headers.authorization.startsWith('Bearer ')){
idToken = req.headers.authorization.split('Bearer ')[1]
}else{
console.error('No token found')
return res.status(403).json({error: 'Unauthorized'})
}
//verify that this token was issued by our application
admin.auth().verifyIdToken(idToken)
.then(decodedToken => {
req.user = decodedToken
return db.collection('users')
.where('userId', '==', req.user.uid)
.limit(1) //limits results to one document
.get()
})
.then(data => {
req.user.handle = data.docs[0].data().handle //data() is a function that extracts data from document
return next() //next() is a function that allows request to proceed to shout post route
})
.catch(err => {
console.error('Error while verifying token', err)
return res.status(403).json(err)
})
}
app.post('/shout', FBauth, (req,res) => {
const newShout = {
body: req.body.body,
userHandle: req.body.userHandle, //userhandle identifies who is owner of shout
createdAt: new Date().toISOString()
}
db
.collection('shouts')
.add(newShout)
.then((doc) => {
res.json({message: `document ${doc.id} created successfully`})
})
.catch((err) =>{
res.status(500).json({error: 'something went wrong'})
console.error(err)
})
})
//helper function to determine if string is empty or not
//note: .trim() removes whitespace from email field
const isEmpty = (string) => {
if (string.trim()=== '') {
return true
} else {
return false
}
}
//helper function to determine if valid email
const isEmail = (email) => {
const regEx = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (email.match(regEx)) {
return true
} else {
return false
}
}
//Sign up route
app.post('/signup', (req,res) => {
//here we need to extract form data from request body
const newUser = {
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
handle: req.body.handle,
}
let errors = {}
if(isEmpty(newUser.email)){
errors.email = 'Email must not be empty'
} else if(!isEmail(newUser.email)) {
errors.email = 'Must be a valid email address'
} //if not empty, need to check if valid email
if(isEmpty(newUser.password)){
errors.password = 'Must not be empty'
}
if(newUser.password !== newUser.confirmPassword) {
errors.confirmPassword = 'Passwords must match'
}
if(isEmpty(newUser.handle)){
errors.handle = 'Must not be empty'
}
if(Object.keys(errors).length>0) {
return res.status(400).json(errors)
}
//sign up user
let token
db.doc(`/users/${newUser.handle}`).get()
.then((doc)=> {
if(doc.exists){
return res.status(400).json({handle: 'this handle is already taken'})
} else {
return firebase
.auth()
.createUserWithEmailAndPassword(newUser.email, newUser.password)
}
})
.then(data => {
userId = data.user.uid
return data.user.getIdToken()
})
.then(token => {
token=token
const userCredentials = {
handle: newUser.handle,
email: newUser.email,
createdAt: new Date().toISOString(),
userId:userId
}
db.doc(`/users/${newUser.handle}`).set(userCredentials)
return res.status(201).json({token})
})
.then(() => {
return res.status(201).json({token})
})
.catch(err => {
console.error(err)
return res.status(500).json({error:err.code})
})
})
//token is used to access route that is protected
//login route
app.post('/login', (req,res) => {
const user = {
email: req.body.email,
password: req.body.password
}
let errors = {}
if(isEmpty(user.email)){
errors.email = 'Must not be empty'
}
if(isEmpty(user.password)){
errors.password = 'Must not be empty'
}
if(Object.keys(errors).length >0) {
return res.status(400).json(errors)
}
firebase.auth().signInWithEmailAndPassword(user.email, user.password)
.then(data => {
return data.user.getIdToken()
})
.then(token => {
return res.json({token})
})
.catch(err => {
console.error(err)
if(err.code ==="auth/wrong-password" ){
return res.status(403).json({general: 'Wrong credentials, please try again'})
} else
return res.status(500).json({error: err.code})
})
})
exports.api = functions.https.onRequest(app)

Mongoose Ignore Required

I have this User schema:
email: {
type: String,
required: true
},
name: {
type: String,
required: true
},
password: {
type: String,
required: true
}
When you do a POST (/api/user-add), I want all the fields to be required. But when I do a login (/api/login) then I only need the email and password fields. My problem is, in my login code I eventually get to this function:
staffSchema.methods.generateToken = function(callback) {
var token = jwt.sign(this._id.toHexString(), config.SECRET);
this.token = token;
this.save(function(err, staff) {
if (err) return callback(err);
callback(null, staff);
});
}
And here it thows an error because the name field is required. How do I bypass this. I am looking for something like this I assume:
this.save(function(err, staff) {
if (err) return callback(err);
callback(null, staff);
}).ignoreRequired('name');
When You Login using JWT token this is a basic example to generate token and authenticate user without store token
Note :
Example to authenticate the user without store token in DB
*Login Method
const jwt = require('./jwt');
userCtr.authenticate = (req, res) => {
const {
email, password,
} = req.body;
const query = {
email: email,
};
User.findOne(query)
.then((user) => {
if (!user) {
//return error user not found.
} else {
if (passwordHash.verify(password, user.password)) { // verify password
const token = jwt.getAuthToken({ id: user._id });
const userData = _.omit(user.toObject(), ['password']); // return user data
return res.status(200).json({ token, userData });
}
//return error password not match
}
})
.catch((err) => {
});
};
*jwt.js
const jwt = require('jwt-simple');
const logger = require('./logger');
const jwtUtil = {};
jwtUtil.getAuthToken = (data) => {
return jwt.encode(data, process.env.JwtSecret);
};
jwtUtil.decodeAuthToken = (token) => {
if (token) {
try {
return jwt.decode(token, process.env.JwtSecret);
} catch (err) {
logger.error(err);
return false;
}
}
return false;
};
module.exports = jwtUtil;
*use middleware to prevent another route to access.
userRouter.post('/update-profile', middleware.checkUser, userCtr.updateProfile);
*middleWare.js
middleware.checkUser = (req, res, next) => {
const { headers } = req;
if (_.isEmpty(headers.authorization)) {
//return error
} else {
const decoded = jwt.decodeAuthToken(headers.authorization.replace('Bearer ', ''));
if (decoded) {
User.findOne({ _id: decoded.id })
.then((user) => {
if (user) {
req.user = user;
next();
} else {
//error
}
})
.catch((err) => {
//errror
});
req.user = decoded;
} else {
//error
}
}
};

Resources