Send POST data using Send Grid API for verification email - node.js

I am having issues posting to send a verification email. I am using ReactJS front end NodeJS backend and MongoDB database. I am running npm run dev to make sure my backend server is running when testing in Postman and gives me an error Cannot Post /api/verify-email I am not getting any other error code so having a hard time trouble shooting. I am using Send Grid API to send the verification email.
verifyEmailRoute.js
import { ObjectId } from 'mongodb';
import jwt from 'jsonwebtoken';
import { getDbConnection } from '../src/db';
export const verifyEmailRoute = {
path: 'http://localhost:8080/api/verify-email',
method: 'put',
handler: async (req, res) => {
const { verificationString } = req.body;
const db = await getDbConnection('react-auth-db');
const result = await db.collection('users').findOne({ verificationString });
if (!result) return res.status(401).json({ message: 'The email verification code is incorrect' });
const { _id: id, email, info } = result;
await db.collection('users').updateOne({ _id: ObjectId(id) }, { $set: { isVerified: true } });
jwt.sign({ id, email, isVerified: true, info }, process.env.JWT_SECRET, { expiresIn: '2d' }, (err, token) => {
if (err) {
return res.status(500).json(err);
}
res.status(200).json({ token });
});
},
};
emailVerificationLandingPage.js
import { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { useToken } from '../src/auth/useToken';
import { EmailVerificationSuccess } from './EmailVerificationSuccess';
import { EmailVerificationFail } from './EmailVerificationFail';
export const EmailVerificationLandingPage = () => {
const [isLoading, setIsLoading] = useState(true);
const [isSuccess, setIsSuccess] = useState(false);
const [user, setUser] = useState(null);
const { verificationString } = useParams();
const [token, setToken] = useToken();
useEffect(() => {
const loadVerification = async () => {
try {
const response = await fetch.put('http://localhost:8080/api/verify-email', { verificationString });
const { token } = response.data;
setToken(token);
console.log(token);
setIsSuccess(true);
setIsLoading(false);
} catch (error) {
setIsSuccess(false);
setIsLoading(false);
}
}
loadVerification();
}, [setToken, verificationString]);
console.log(token);
if (isLoading) return <p>Loading...</p>;
if (!isSuccess) return <EmailVerificationFail />
return <EmailVerificationSuccess />
}
sendEmail.js
import sendgrid from '#sendgrid/mail';
sendgrid.setApiKey(process.env.SENDGRID_API_KEY);
export const sendEmail = ({ to, from, subject, text, html }) => {
const msg = { to, from, subject, text, html };
return sendgrid.send(msg);
}
signUpRoute.js
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { v4 as uuid } from 'uuid';
import { getDbConnection } from '../src/db';
import { sendEmail } from '../src/util/sendEmail';
export const signUpRoute = {
path: '/api/signup',
method: 'post',
handler: async (req, res) => {
const { email, password } = req.body;
// Make sure there's no existing user with that email - no verification yet
const db = getDbConnection('react-auth-db');
const user = await db.collection('users').findOne({ email });
if (user) {
console.log("found user", user)
return res.sendStatus(409).json(user); // 409 is the "conflict" error code
}
// Generate the salt first
const salt = uuid();
const pepper = process.env.PEPPER_STRING;
// Encrypt the password
const passwordHash = await bcrypt.hash(salt + password + pepper, 10);
const verificationString = uuid();
// Store email and password hash in database (i.e. create user) - you'll also want to get the id
const startingInfo = {
firstName: '',
lastName: '',
dob: '',
}
const result = await db.collection('users').insertOne({
email,
isVerified: false,
verificationString,
passwordHash,
salt,
info: startingInfo,
});
const { insertedId } = result;
try {
await sendEmail({
to: email,
from: 'mdolly01#gmail.com',
subject: 'Welcome to Tool Right Please verify your email',
text: `
Thanks for signing up! To verify your email, you just need to click the link below:
http://localhost:3000/verify-email/${verificationString}
`
});
} catch (e) {
console.log(e);
throw new Error(e);
}
jwt.sign({
id: insertedId,
isVerified: false,
email, // Do NOT send the salt back to the user
info: startingInfo,
},
process.env.JWT_SECRET,
{
expiresIn: '2d',
},
(err, token) => {
if (err) {
return res.status(500).send(err);
}
return res.status(200).json({token});
});
},
};

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.

While Verifying email and reseting password, only the first created/registered user's token is being valid or verified

Scenario : When I create/register user1 ,the verification mail is sent to that email id and he(user1) is being verified successfully and I am able to change password for user1. After creating user1 , I am creating/registering user2 ,where the verification email is sent to the account .After clicking the link , it's becomes INVALID Overall , I am only able to create one user
Languages used : MERN stack
Backend => route.js :
const express = require("express");
const router = express.Router();
const User = require("../models/userModel");
const Doctor = require("../models/doctorModel");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const authMiddleware = require("../middlewares/authMiddleware");
const sendEmail = require("../utils/sendMail");
const Token = require("../models/tokenModel");
const Appointment = require("../models/appointmentModel");
const moment = require("moment");
router.post("/register", async (req, res) => {
try {
const userExists = await User.findOne({ email: req.body.email });
if (userExists) {
return res
.status(200)
.send({ message: "User already exists", success: false });
}
const password = req.body.password;
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
req.body.password = hashedPassword;
const newuser = new User(req.body);
const result = await newuser.save();
await sendEmail(result, "verifyemail");
res
.status(200)
.send({ message: "User created successfully", success: true });
} catch (error) {
console.log(error);
res
.status(500)
.send({ message: "Error creating user", success: false, error });
}
});
router.post("/login", async (req, res) => {
try {
const result = await User.findOne({ data: req.body.userId });
console.log(result);
const user = await User.findOne({ email: req.body.email });
if (!user) {
return res
.status(200)
.send({ message: "User does not exist", success: false });
}
if (user.isVerified === false) {
return res
.status(200)
.send({ message: "User not Verified", success: false });
}
const isMatch = await bcrypt.compare(req.body.password, user.password);
if (!isMatch) {
return res
.status(200)
.send({ message: "Password is incorrect", success: false });
} else {
const dataToBeSentToFrontend = {
id: user._id,
email: user.email,
name: user.name,
};
const token = jwt.sign(dataToBeSentToFrontend, process.env.JWT_SECRET, {
expiresIn: "1d",
});
res
.status(200)
.send({ message: "Login successful", success: true, data: token });
}
} catch (error) {
console.log(error);
res
.status(500)
.send({ message: "Error logging in", success: false, error });
}
});
router.post("/get-user-info-by-id", authMiddleware, async (req, res) => {
try {
const user = await User.findOne({ _id: req.body.userId });
user.password = undefined;
if (!user) {
return res
.status(200)
.send({ message: "User does not exist", success: false });
} else {
res.status(200).send({
success: true,
data: user,
});
}
} catch (error) {
res
.status(500)
.send({ message: "Error getting user info", success: false, error });
}
});
router.post("/send-password-reset-link", async (req, res) => {
try {
const result = await User.findOne({ email: req.body.email });
await sendEmail(result, "resetpassword");
res.send({
success: true,
message: "Password reset link sent to your email successfully",
});
} catch (error) {
res.status(500).send(error);
}
});
router.post("/resetpassword", async (req, res) => {
try {
const tokenData = await Token.findOne({ token: req.body.token });
if (tokenData) {
const password = req.body.password;
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
await User.findOneAndUpdate({
_id: tokenData.userid,
password: hashedPassword,
});
await Token.findOneAndDelete({ token: req.body.token });
res.send({ success: true, message: "Password reset successfull" });
} else {
res.send({ success: false, message: "Invalid token" });
}
} catch (error) {
res.status(500).send(error);
}
});
router.post("/verifyemail", async (req, res) => {
try {
const tokenData = await Token.findOne({ token: req.body.token });
if (tokenData) {
await User.findOneAndUpdate({ _id: tokenData.userid, isVerified: true });
await Token.findOneAndDelete({ token: req.body.token });
res.send({ success: true, message: "Email Verified Successlly" });
} else {
res.send({ success: false, message: "Invalid token" });
}
} catch (error) {
res.status(500).send(error);
}
});
Backend => sendEmail.js :
const nodemailer = require("nodemailer");
const bcrypt = require("bcrypt");
const Token = require("../models/tokenModel");
module.exports = async (user, mailType) => {
try {
const transporter = nodemailer.createTransport({
service: "gmail",
host: "smtp.gmail.com",
port: 587,
secure: true,
auth: {
user: "sh***********th#gmail.com",
pass: "e**************l",
},
});
const encryptedToken = bcrypt
.hashSync(user._id.toString(), 10)
.replaceAll("/", "");
const token = new Token({
userid: user._id,
token: encryptedToken,
});
await token.save();
let mailOptions, emailContent;
if (mailType === "verifyemail") {
emailContent = `<div><h1>Please click on the below link to verify your email address</h1> ${encryptedToken} </div>`;
mailOptions = {
from: "sh************th#gmail.com",
to: user.email,
subject: "Verify Email For MERN Auth",
html: emailContent,
};
} else {
emailContent = `<div><h1>Please click on the below link to reset your password</h1> ${encryptedToken} </div>`;
mailOptions = {
from: "shanshangeeth#gmail.com",
to: user.email,
subject: "Reset Password",
html: emailContent,
};
}
await transporter.sendMail(mailOptions);
} catch (error) {
console.log(error);
}
};
Backend => authMiddleware.js :
const jwt = require("jsonwebtoken");
module.exports = async (req, res, next) => {
try {
const token = req.headers["authorization"].split(" ")[1];
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err) {
return res.status(401).send({
message: "Auth failed",
success: false,
});
} else {
req.body.userId = decoded.id;
next();
}
});
} catch (error) {
return res.status(401).send({
message: "Auth failed",
success: false,
});
}
};
Backend => tokenmodel.js :
const mongoose = require("mongoose");
const tokenSchema = new mongoose.Schema(
{
userid: {
type: String,
required: true,
},
token: {
type: String,
required: true,
},
},
{ timestamps: true }
);
const tokenModel = mongoose.model("tokens", tokenSchema);
module.exports = tokenModel;
Backend => userModel.js
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
isVerified: {
type: Boolean,
default: false,
},
isDoctor: {
type: Boolean,
default: false,
},
isDoctor: {
type: Boolean,
default: false,
},
isAdmin: {
type: Boolean,
default: false,
},
seenNotifications: {
type: Array,
default: [],
},
unseenNotifications: {
type: Array,
default: [],
},
},
{
timestamps: true,
}
);
const userModel = mongoose.model("users", userSchema);
module.exports = userModel;
Frontend => VerifyEmail.js
path="/verifyemail/:token" in app.js inside PublicRoute
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { toast } from "react-hot-toast";
import axios from "axios";
function VerifyEmail() {
const [emailVerified, setEmailVerified] = useState("");
const params = useParams();
const verifyToken = async () => {
try {
toast.loading();
const response = await axios.post("/api/user/verifyemail", {
token: params.token,
});
if (response.data.success) {
setEmailVerified("true");
} else {
setEmailVerified("false");
}
toast.dismiss();
} catch (error) {
toast.dismiss();
setEmailVerified("false");
}
};
useEffect(() => {
verifyToken();
}, []);
console.log(emailVerified);
return (
<div className="flex min-h-screen p-5 justify-center items-center">
{emailVerified == "" && (
<h1 className="text-primary text-4xl">
Please wait we are verifying your email
</h1>
)}
{emailVerified == "true" && (
<h1 className="text-primary text-4xl">
Your email verified successfully
</h1>
)}
{emailVerified == "false" && (
<h1 className="text-primary text-4xl">
Invalid or Expired Token
{console.log(emailVerified)}
</h1>
)}
</div>
);
}
export default VerifyEmail;
Frontend =>ProtectedRoute.js
import React from "react";
import { Navigate, useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import axios from "axios";
import { setUser } from "../redux/userSlice";
import { showLoading, hideLoading } from "../redux/alertsSlice";
function ProtectedRoute(props) {
const { user } = useSelector((state) => state.user);
const dispatch = useDispatch();
const navigate = useNavigate();
const getUser = async () => {
try {
dispatch(showLoading());
const response = await axios.post(
"/api/user/get-user-info-by-id",
{ token: localStorage.getItem("token") },
{
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
}
);
console.log('TOKEN ("token") : ', localStorage.getItem("token"));
dispatch(hideLoading());
if (response.data.success) {
dispatch(setUser(response.data.data));
console.log(response.data.data);
} else {
localStorage.clear();
navigate("/login");
}
} catch (error) {
dispatch(hideLoading());
localStorage.clear();
navigate("/login");
}
};
useEffect(() => {
if (!user) {
getUser();
}
}, [user]);
if (localStorage.getItem("token")) {
return props.children;
} else {
return <Navigate to="/login" />;
}
}
export default ProtectedRoute;
Frontend=> VerifyEmail.js
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { toast } from "react-hot-toast";
import axios from "axios";
function VerifyEmail() {
const [emailVerified, setEmailVerified] = useState("");
const params = useParams();
const verifyToken = async () => {
try {
toast.loading();
const response = await axios.post("/api/user/verifyemail", {
token: params.token,
});
if (response.data.success) {
setEmailVerified("true");
} else {
setEmailVerified("false");
}
toast.dismiss();
} catch (error) {
toast.dismiss();
setEmailVerified("false");
}
};
useEffect(() => {
verifyToken();
}, []);
console.log(emailVerified);
return (
<div className="flex min-h-screen p-5 justify-center items-center">
{emailVerified == "" && (
<h1 className="text-primary text-4xl">
Please wait we are verifying your email
</h1>
)}
{emailVerified == "true" && (
<h1 className="text-primary text-4xl">
Your email verified successfully
</h1>
)}
{emailVerified == "false" && (
<h1 className="text-primary text-4xl">
Invalid or Expired Token
{console.log(emailVerified)}
</h1>
)}
</div>
);
}
export default VerifyEmail;
Frontend => userSlice.js
import { createSlice } from "#reduxjs/toolkit";
export const userSlice = createSlice({
name: "user",
initialState: {
user: null
},
reducers: {
setUser: (state , action) => {
state.user = action.payload;
}
},
});
export const { setUser , reloadUserData } = userSlice.actions;
When I create/register user1 , the verification mail is sent to that email id and he(user1) is being verified successfully and I am able to change password for user1. After creating user1 , I am creating/registering user2 ,where the verification email is sent to the account .After clicking the link , it's becomes INVALID Overall , I am only able to create one user who's being verified

axios get method doesn't send any data in to my node backend using react native

When I console.log the variable refToken before the get request the refToken shows what it contains but after that nothing, and my backend sends me the error 401 which means no token was provided!!
I am really confused here
utility file for expo-secure-store
import * as SecureStore from 'expo-secure-store';
const saveRefreshToken = async (value: string) => {
try {
await SecureStore.setItemAsync("refreshToken", value);
} catch (e) {
console.log("Cannot set refresh token")
}
}
const getRefreshToken = async () => {
try {
return await SecureStore.getItemAsync("refreshToken");
} catch (e) {
console.log("can't get requested refreshToken", e);
}
}
const deleteRefreshToken = async () => {
try {
await SecureStore.deleteItemAsync("refreshToken");
} catch (e) {
console.log("cannot delete refreshToken ", e);
}
}
export default {
saveRefreshToken,
getRefreshToken,
deleteRefreshToken
};
React native code
import axios from "../api/axios";
import useAuth from "./useAuth";
import storage from "../utility/storage";
import jwtDecode from "jwt-decode";
const useRefreshToken = () => {
const {setAuth, auth} = useAuth();
return async () => {
const refToken = await storage.getRefreshToken();
// withCredentials: true,
const response = await axios.get(`/auth/refresh/`, {
params: {refreshToken: refToken},
});
//#ts-ignore
setAuth({user: jwtDecode(response.data.accessToken), accessToken: response.data.accessToken});
return response.data.accessToken;
};
}
export default useRefreshToken;
Node.js backend part that deals with this request
// TODO: Generate new access token from refresh
export const refreshTokenSignIn = (
req: express.Request,
res: express.Response,
next: express.NextFunction
) => {
// const refreshToken = req.cookies.jwt;
const refreshToken = req.body.refreshToken;
try {
// Check if the refresh token is not null
if (!refreshToken)
return res.status(401).json({message: "No token provided!"});
// console.log(refreshToken);
const sql = `select * from token_records where refresh_token = '${refreshToken}'`;
// Check if there is such refresh token for the current user
db.query(
sql,
[refreshToken],
(err: QueryError, result: RowDataPacket[]) => {
if (err) return next(err);
if (result.length === 0)
return res.status(403).json({message: "You don't have access"});
//#ts-ignore
jwt.verify(
refreshToken,
//#ts-ignore
process.env.JWT_REFRESH_SECRET,
(err2: VerifyErrors, user: JwtPayload) => {
if (err2) return res.status(403).json({message: "You don't have access"});
const accessToken = jwt.sign(
{
user_id: user.user_id,
firstname: user.firstname,
lastname: user.lastname,
username: user.username,
email: user.email,
role: user.role,
},
//#ts-ignore
process.env.JWT_SECRET
);
res.status(200).json({accessToken: accessToken});
next();
}
);
}
);
} catch (e) {
console.log(e);
next();
}
};

React Application error "The server responded with error 401 (unauthorized) "

I am working on a user registration project on ReactJS and got stuck on a problem when I try to activate the user account. The backend server is giving me the error 401: Failed to load resource: the server responded with a status of 401 (Unauthorized). What might be the problem here, I was not able to find out any solution related to my code, can anyone help ??
Here is my code for Activation.jsx:
import React, { useState, useEffect } from 'react';
import authSvg from '../assests/welcome.svg';
import axios from 'axios';
import jwt_decode from 'jwt-decode';
import { isAuth } from '../helpers/auth';
import { Navigate , useParams} from 'react-router-dom';
const Activate = ({ match }) => {
const [formData, setFormData] = useState({
name: '',
token: '',
show: true
});
match = useParams();
useEffect(() => {
let token = match.token;
console.log(token);
let { name } = jwt_decode(token);
if (token) {
setFormData({ ...formData, name, token });
}
console.log(token, name);
}, [match.params]);
const { name, token, show } = formData;
const handleSubmit = e => {
e.preventDefault();
axios
.post(`${process.env.REACT_APP_API_URL}/activation`, {
token
})
.then(res => {
setFormData({
...formData,
show: false
});
console.log(res.data.message);
})
.catch(err => {
console.log(err);
});
};
Here is the code from activation controller :
const User = require('../models/auth.model');
const expressJwt = require('express-jwt');
const _ = require('lodash');
const { OAuth2Client } = require('google-auth-library');
const fetch = require('node-fetch');
const { validationResult } = require('express-validator');
const jwt_decode = require('jwt-decode')
const { errorHandler } = require('../helpers/dbErrorHandling');
const nodemailer = require('nodemailer')
exports.activationController = (req, res) => {
const { token } = req.body;
if (token) {
jwt_decode.verify(token, process.env.JWT_ACCOUNT_ACTIVATION, (err, decoded) => {
if (err) {
console.log('Activation error');
return res.status(401).json({
errors: 'Expired link. Signup again'
});
} else {
const { name, email, password } = jwt_decode(token);
console.log(email);
const user = new User({
name,
email,
password
});
user.save((err, user) => {
if (err) {
console.log('Save error', errorHandler(err));
return res.status(401).json({
errors: errorHandler(err)
});
} else {
return res.json({
success: true,
message: user,
message: 'Signup success'
});
}
});
const apiKey = user._id;
user.apiKey = apiKey
user.save((err) => {
console.log(err);
})
}
});
} else {
return res.json({
message: 'error happening please try again'
});
}
};
As you have said in the comments , I think you have apiKey and path as an object properties in your user model which are not filled , and also the problem is you are using jwt_decode for verify and sign purposes which is wrong , the purpose for jwt_decode here is for decoding the token and nothing else , so use jsonwebtoken library for verfication and sign purposes .
Also remove the api key generation code , as what are you doing you are calling user.save() method 2 times in a row so the first one hasn't even finished saving before the 2nd one gets called .

How to properly integrate Mongoose relational database

can you help me look at this code to find out where I am making it wrong ?
I have my mongoose schema that am referencing child. What I want is to create a user and embed his payment details as a reference. my current result now, allows me to create anew user and the problems comes from when I want to update the user schema with payment details. If I send a request in postman, the request keep on loading until I cancel it. and what happend is if I try to get the userInfo, I will see that the payment_Id is reference in the schema but I can called .populate method on the parent schema. below is the....
export const expoSignUp = async (req, res) => {
const { firstname, lastname, middlename, username, email, phoneNo , password } = req.body
try {
const userReg = await Expo.findOne({ username })
if (userReg) {
res.status(403).json({ message: "Username already taken"})
} else {
const encryptPass = CryptoJS.AES.encrypt(password, 'secret key 123').toString();
const userData = await Expo.create({
firstname, lastname, middlename, username, email, phoneNo, password: encryptPass
});
const result = jwt.sign({firstname, lastname, middlename, username, email, phoneNo},"secrete", {expiresIn:"24"})
res.status(200).json({ userData, result })
}
} catch (err) {
res.status(500).json({ message: err.message });
}
}
export const expoSignIn = async (req, res) => {
const { password, email, username } = req.body;
try {
const userLogin = await Expo.findOne({ username })
if (!userLogin) {
res.status(401).json({ message: "username is incorrect"})
} else {
const decryptPass = CryptoJS.AES.decrypt(userLogin.password, 'secret key 123');
var originalPass = decryptPass.toString(CryptoJS.enc.Utf8);
if (password !== originalPass) {
res.status(403).json({ message: "Login credentials is incorrect" })
} else {
const result = jwt.sign({ username, email, _id: userLogin._id }, "secrete", { expiresIn: "24" });
const {password, ...others} = userLogin._doc
res.status(200).json({ others, result })
}
}
} catch (error) {
res.status(500).json({message: error.message})
}
}
export const getAllExpoUsers = async (req, res) => {
try {
const getUsers = await Expo.find()
res.status(200).json(getUsers)
} catch (err) {
res.status(err)
}
}
export const paymentInfo = async (req, res) => {
const {
userId,
tx_ref,
amount,
currency,
payment_options,
customer: {
email,
phonenumber,
fullname,
},
customizations: {
title,
description,
logo
}
} = req.body;
try {
const userPaymentInfo = await Payment.create({
tx_ref,
amount,
currency,
payment_options,
customer: {
email,
phonenumber,
fullname,
},
customizations: {
title,
description,
logo
}
})
const newPaymentInfo = await Expo.findById({ _id: userPayment })
res.status(newPaymentInfo)
} catch (error) {
res.status(500).json({message:error.message})
}
}

Resources