Access token giving promise - reactjs

So I have jwt authentication with access and refresh tokens. But the problem is when the access token expires and i generate a new access token on the frontend (react). It gives me a promise
backend/routes/auth.js (Route to refresh token and where im generating the refresh token and storing it (login route))
router.post("/login", async (req, res) => {
try {
// Validating user
const { error } = loginValidation(req.body);
if (error) return res.status(400).json(error.details[0].message);
// Making sure email is correct
const user = await User.findOne({ email: req.body.email });
if (!user) return res.status(400).json("Invalid email or password");
// Making sure the password is correct
const validPass = await bcrypt.compare(req.body.password, user.password);
if (!validPass) return res.status(400).json("Invalid email or password");
const userPayload = {
_id: user._id,
displayname: user.displayname,
username: user.username,
email: user.email,
bookmarkedTweets: user.bookmarkedTweets,
likedTweets: user.likedTweets,
followers: user.followers,
following: user.following,
date: user.date,
month: user.month,
day: user.day,
year: user.year,
profilePic: user.profilePic,
};
// Generating access token
const accessToken = generateAccessToken(userPayload);
// Generating refresh token
const refreshToken = jwt.sign(
user.toJSON(),
process.env.REFRESH_TOKEN_SECRET
);
// Getting info for refresh token
const newRefreshToken = new RefreshToken({
refreshToken: refreshToken,
});
// Saving refresh token into db
await newRefreshToken.save();
res.json({
_id: user._id,
displayname: user.displayname,
username: user.username,
email: user.email,
password: user.password,
bookmarkedTweets: user.bookmarkedTweets,
likedTweets: user.likedTweets,
followers: user.followers,
following: user.following,
date: user.date,
month: user.month,
day: user.day,
year: user.year,
profilePic: user.profilePic,
accessToken: accessToken,
refreshToken: refreshToken,
});
} catch (error) {
res.sendStatus(500);
console.log(error);
}
});
router.post("/refresh/token", async (req, res) => {
try {
// Getting refresh token
const refreshToken = req.body.token;
// Finding refresh token
const _refreshToken = await RefreshToken.findOne({ refreshToken: refreshToken });
// Making sure there is a refresh token and that refresh token exists in db
if (refreshToken == null) return res.sendStatus(401);
if (!_refreshToken) return res.sendStatus(403);
// Vaifying refresh token
jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
const userPayload = {
_id: user._id,
displayname: user.displayname,
username: user.username,
email: user.email,
bookmarkedTweets: user.bookmarkedTweets,
likedTweets: user.likedTweets,
followers: user.followers,
following: user.following,
month: user.month,
day: user.day,
year: user.year,
date: user.date,
profilePic: user.profilePic,
};
// Generating access token
const accessToken = generateAccessToken(userPayload);
res.json({ accessToken });
});
} catch (error) {
res.sendStatus(500);
}
});
backend/middlewares/authenticateToken.js
const jwt = require("jsonwebtoken");
require("dotenv").config();
module.exports = function authenticateToken(req, res, next) {
const authHeader = req.headers["authorization"]; // Getting auth header
const token = authHeader && authHeader.split(" ")[1]; // Getting access token from auth header
if (token == null) return res.sendStatus(401);
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403); // Making sure the token is valid
req.user = user;
next();
});
};
backend/utils/generateAccessToken.js
const jwt = require("jsonwebtoken");
require("dotenv").config();
module.exports = function (user) {
return jwt.sign(user, process.env.ACCESS_TOKEN_SECRET, { expiresIn: "15s" });
};
frontend/src/api/axios.js
import axios from "axios";
const BASE_URL = "http://localhost:5000";
const accessToken = sessionStorage.getItem("accessToken");
const refreshToken = localStorage.getItem("refreshToken");
export default axios.create({
baseURL: BASE_URL,
headers: { "Content-Type": "application/json" },
});
const client = axios.create({ baseURL: BASE_URL });
export const axiosAuth = async ({ ...options }) => {
// Sending access token with request
client.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
const onSuccess = (response) => response;
const onError = (error) => {
if (error.response.status === 403) {
// Making function to generate new access token
const refresh = async () => {
const { data } = await axios.post(`${BASE_URL}/auth/refresh/token`, {
token: refreshToken,
});
return data;
};
// Generating access token
const newAccessToken = refresh();
sessionStorage.setItem("accessToken", newAccessToken);
return client({ ...options });
}
throw error;
};
return client(options).then(onSuccess).catch(onError);
};
frontend/src/modals/Tweet.modal.js (Where im using axiosAuth)
import React, { useState } from "react";
import AccountCircleOutlinedIcon from "#mui/icons-material/AccountCircleOutlined";
import ArrowBackIcon from "#mui/icons-material/ArrowBack";
import PublicOutlinedIcon from "#mui/icons-material/PublicOutlined";
import CollectionsOutlinedIcon from "#mui/icons-material/CollectionsOutlined";
import GifBoxOutlinedIcon from "#mui/icons-material/GifBoxOutlined";
import BarChartOutlinedIcon from "#mui/icons-material/BarChartOutlined";
import SentimentSatisfiedAltOutlinedIcon from "#mui/icons-material/SentimentSatisfiedAltOutlined";
import ScheduleOutlinedIcon from "#mui/icons-material/ScheduleOutlined";
import LocationOnOutlinedIcon from "#mui/icons-material/LocationOnOutlined";
import Loader from "../components/Loader/Loader.comp";
import { useDispatch, useSelector } from "react-redux";
import {
setTweetModal,
setTweetPending,
tweetErrorClear,
tweetFail,
} from "../features/tweet.slice";
import { axiosAuth } from "../api/axios";
function Tweet() {
const [textfield, setTextfield] = useState("");
const { user } = useSelector((state) => state.user);
const { tweetModalIsOpen, error, isLoading } = useSelector(
(state) => state.tweet
);
const { profilePic } = user;
const dispatch = useDispatch();
if (error !== "") {
setTimeout(() => dispatch(tweetErrorClear()), 3000);
}
const handleOnClick = async () => {
dispatch(setTweetPending(true));
try {
await axiosAuth({
url: "/posts/create",
method: "POST",
body: { textfield },
});
} catch (error) {
dispatch(tweetFail(error.response.data));
}
};
return (
<div
className={
tweetModalIsOpen
? `h-screen w-screen absolute inset-0 bg-white py-2 px-4`
: `hidden`
}
>
<div className="flex-items justify-between">
<div
className="p-1 cursor-pointer rounded-full hover:bg-gray-200 transition-color"
onClick={() => dispatch(setTweetModal(false))}
>
<ArrowBackIcon style={{ fontSize: "1.5rem" }} />
</div>
<button
className="py-1 px-4 transition-color rounded-full bg-blue-500 text-white font-bold hover:bg-blue-600"
onClick={() => handleOnClick()}
>
{isLoading ? <Loader forPage={false} /> : <h1>Tweet</h1>}
</button>
</div>
<div className="flex mt-6 space-x-2">
{profilePic === "" ? (
<AccountCircleOutlinedIcon style={{ fontSize: "2rem" }} />
) : (
<img src={profilePic} alt="profile_pic" />
)}
<div>
<textarea
name="tweet"
id="tweet"
rows="4"
value={textfield}
onChange={(e) => setTextfield(e.target.value)}
className="w-screen outline-none text-xl text-gray-700 placeholder:text-gray-600"
placeholder="What's happening?"
></textarea>
<div className="flex-items space-x-2 text-blue-400 font-bold py-0.5 px-2 rounded-full hover:bg-blue-50 transition-color cursor-pointer w-max">
<PublicOutlinedIcon style={{ fontSize: "1.5rem" }} />
<h1>Everyone can reply</h1>
</div>
<div className="ring-1 ring-gray-100 my-2 w-[75%]" />
<div className="flex-items space-x-2 text-blue-500">
<div className="tweet-icon">
<CollectionsOutlinedIcon style={{ fontSize: "1.5rem" }} />
</div>
<div className="tweet-icon">
<GifBoxOutlinedIcon style={{ fontSize: "1.5rem" }} />
</div>
<div className="tweet-icon">
<BarChartOutlinedIcon style={{ fontSize: "1.5rem" }} />
</div>
<div className="tweet-icon">
<SentimentSatisfiedAltOutlinedIcon
style={{ fontSize: "1.5rem" }}
/>
</div>
<div className="tweet-icon">
<ScheduleOutlinedIcon style={{ fontSize: "1.5rem" }} />
</div>
<div className="tweet-icon">
<LocationOnOutlinedIcon style={{ fontSize: "1.5rem" }} />
</div>
</div>
</div>
</div>
{error && <h1 className="error err-animation">{error}!</h1>}
</div>
);
}
export default Tweet;
Thanks in advance!

I assume that _refreshToken is the promise you refer to. In order to obtain the eventual value of that promise (that is, the refresh token itself), add async to your middleware function and await to the assignment statement:
router.post("/refresh/token", async (req, res) => {
try {
const refreshToken = req.body.token;
const _refreshToken = await RefreshToken.findOne({ refreshToken: refreshToken });
Same in frontend/src/api/axios.js:
const onError = async (error) => {
...
const newAccessToken = await refresh();

Related

REACT JS: Crud table delete

I have a parent component that sends props to a CRUD Table, i have a problem with deleting the items i want to delete the item with the selected id and i want to send both the email and id in the body of the request. i create the Info just to send it to the CRUD table to be shown because i don't want the entire pendingList to be shown. The id sent to the request when i click on deleteIcon={<IoTrashOutline style={{fontSize: '18px', color: 'red', cursor: 'pointer'}} onClick={() => handleDeleteProduct(info.id)} />} is undefined and i get it cause info is an array the problem is i'm not sure how to get the specific id of the item i want to delete and send it to the request. Any suggestions?
const UserNewDevice = () => {
const [pendingList, setPendingList] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
const email = localStorage.getItem("email")
useEffect(() => {
const fetchPendingList = async () => {
setIsLoading(true);
try {
const res = await fetch('http://localhost:5000/prods/user_product', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem("token")}`
},
body: JSON.stringify(email),
});
if (!res.ok) {
const data = await res.json();
throw new Error(data.msg);
}
const data = await res.json();
setPendingList(data);
} catch (err) {
setError(err.message);
} finally {
setIsLoading(false);
}
};
fetchPendingList();
}, []);
const info = pendingList.map(item => {
return {
id: item._id,
produit: item.produits,
marque: item.marque,
référence: item.référence,
installation: item.annéeInstallation,
entretenu: item.entretenu,
année: item.selectedYearEntretenu,
}
});
const handleDeleteProduct = async (id) => {
try {
const email = localStorage.getItem("email");
console.log('id', id)
const res = await fetch('http://localhost:5000/prods/remove_product', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('token')}`
},
body: JSON.stringify({ id, email })
});
if (!res.ok) {
const data = await res.json();
throw new Error(data.msg);
}
const data = await res.json();
setPendingList(pendingList.filter(item => item.id !== id));
} catch (err) {
console.error(err);
setError(err.message);
}
};
return (
<>
<div className="mt-10 sm:mt-0 w-[92%] ml-12">
<div className="md:grid md:grid-cols-2 md:gap-6">
<div className="mt-5 md:col-span-2 md:mt-0">
<CRUDTable
data={info}
link={`/user-projets-details/`}
pencilIcon={<IoPencil style={{fontSize: '18px', cursor: 'pointer', color: 'green'}}/>}
eyeIcon={<IoEyeOutline style={{fontSize: '18px', cursor: 'pointer', color: '#f8c408'}}/>}
deleteIcon={<IoTrashOutline style={{fontSize: '18px', color: 'red', cursor: 'pointer'}} onClick={() => handleDeleteProduct(info.id)} />}
/>
</div>
</div>
</div>
</>
)
}
export default UserNewDevice
The issue is that info is an array, not an object, and info.id is not a valid reference. To get the specific id of the item you want to delete, you need to pass it as a parameter when calling the handleDeleteProduct function from within the deleteIcon prop. You can modify the code as follows:
deleteIcon={(id) => <IoTrashOutline style={{fontSize: '18px', color: 'red', cursor: 'pointer'}} onClick={() => handleDeleteProduct(id)} />}
And when you call it in the map function:
const info = pendingList.map(item => {
return {
id: item._id,
produit: item.produits,
marque: item.marque,
référence: item.référence,
installation: item.annéeInstallation,
entretenu: item.entretenu,
année: item.selectedYearEntretenu,
}
});
Becomes:
const info = pendingList.map(item => {
return {
id: item._id,
produit: item.produits,
marque: item.marque,
référence: item.référence,
installation: item.annéeInstallation,
entretenu: item.entretenu,
année: item.selectedYearEntretenu,
deleteIcon: item._id,
}
});

How do I persist my next-auth user session? so i could use the ID provided to fetch data in other routes

What I want to achieve here is, whenever a user logs in, I want to store the data returned because the data holds an ID that I would use to fetch data in other routes.
When a user successfully logs in, he would be redirected to the /home route and the ID gotten from the session would be used to fetch data. Everything works fine initially, but if I refresh the home page, the user becomes null.
This is what my [...nextauth].js looks like.
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import axios from "axios";
export default NextAuth({
providers: [
CredentialsProvider({
name: "credentials",
credentials: {
username: { label: "Username", type: "text", placeholder: "justin" },
password: {label: "Password",type: "password",placeholder: "******"},
},
async authorize(credentials, req) {
const url = req.body.callbackUrl.split("/auth")[0];
const { username, password } = credentials;
const user = await axios({
url: `${url}/api/user/login`,
method: "POST",
data: {
username: username,
password: password,
},
"content-type": "application/json",
})
.then((res) => {
return res.data;
})
.catch((err) => {
if (err.response.data) {
throw new Error(err.response.data);
} else {
return null;
}
return null;
});
return user;
},
}),
],
callbacks: {
jwt: ({ token, user }) => {
if (user) {
token.user = user;
}
return token;
},
session: ({ session, token }) => {
if (token) {
session.user = token.user;
}
return session;
},
},
pages: {
signIn: "/auth/login",
newUser: "/auth/register",
},
});
and this is what my /home route looks like
import Card from "#/components/card/Card";
import React, { useEffect, useState } from "react";
import styles from "./home.module.css";
import { Ubuntu } from "#next/font/google";
import { useSession } from "next-auth/react";
import { useDispatch, useSelector } from "react-redux";
const ubuntu = Ubuntu({ weight: "500", subsets: ["cyrillic"] });
const getData = async (id) => {
const res = await fetch({
url: "http://localhost:3000/api/note/getall",
method: "POST",
"content-type": "application/json",
data: {
id: id,
},
});
if (!res.ok) {
console.log(id);
throw new Error("Unable to fetch");
} else {
return res.json();
console.log(res);
}
};
function home() {
const colors = ["#E9F5FC", "#FFF5E1", "#FFE9F3", "#F3F5F7"];
const random = Math.floor(Math.random() * 5);
const rc = colors[random];
const [pop, setPop] = useState("none");
const { user } = useSelector((state) => state.user);
const getDataa = async () => {
console.log(user)
const data = await getData(user._id);
console.log(data);
};
useEffect(() => {
if (user) {
alert(user)
}
}, []);
return (
<div className={styles.home}>
<header>
<h3 className={ubuntu.className}>
Hello, <br /> {user?.username}!
</h3>
<input type="text" placeholder="search" />
</header>
<div className={styles.nav}>
<h1 className={ubuntu.className}>Notes</h1>
</div>
<div className={styles.section}>
<div className={styles.inner}>
{/* {data &&
data.map((e) => (
<Card
rawData={e}
color={colors[Math.floor(Math.random() * colors.length)]}
/>
))} */}
</div>
</div>
<div className="new"></div>
</div>
);
}
export default home;
Add this component to your App.js file :
function Auth({ children }) {
const router = useRouter();
const { status } = useSession({
required: true,
onUnauthenticated() {
router.push("/sign-in");
},
});
if (status === "loading") {
return <div>Loading ...</div>;
}
return children;
}
Now in your App function instead of returning <Component {...pageProps} /> you check first if the component has auth property, so you wrapp it with <Auth> to ensure that every component that requires session will only mount when the session finishes loading (that's why the user is null because the session is still loading)
{
Component.auth ? (
<Auth>
<Component {...pageProps} />
</Auth>
) : (
<Component {...pageProps} />
);
}
finally you add .auth = {} to every page in whitch you want the session to be defined (Home in your case)
const Home = () => {
//....
}
Home.auth = {};
This also helps to redirect user to /sign-in page if the session is expired
This code seems like it would create a problem / race-condition since you're mixing two different async promise handling styles:
const user = await axios({
url: `${url}/api/user/login`,
method: "POST",
data: {
username: username,
password: password,
},
"content-type": "application/json",
})
.then((res) => {
return res.data;
})
.catch((err) => {
if (err.response.data) {
throw new Error(err.response.data);
} else {
return null;
}
return null;
});
return user;
It should either be this:
try {
const user = await axios({
url: `${url}/api/user/login`,
method: "POST",
data: {
username: username,
password: password,
},
"content-type": "application/json",
});
return user.data;
} catch (err) {
if (err.response.data) {
throw new Error(err.response.data);
} else {
return null;
}
}
Or this:
axios({
url: `${url}/api/user/login`,
method: "POST",
data: {
username: username,
password: password,
},
"content-type": "application/json",
}).then((res) => {
return res.data;
}).catch((err) => {
if (err.response.data) {
throw new Error(err.response.data);
} else {
return null;
}
return null;
});

Image upload in mern stack using multer not working

I'm trying to upload image in MongoDB using multer and react but I'm unable to post it. I have three inputs in by form i.e title, content and image. If I try to post title and content only it is successfully being posted. I have also added "proxy": "http://localhost:8000", in frontend package.json file
Here is my form
function PostCreate() {
const [title, setTile] = useState("");
const [content, setContent] = useState("");
const [image, setImage] = useState({});
const dispatch = useDispatch();
const post = useSelector((state) => state.postReducer);
const fileOnChange = (e) => {
setImage(e.target.files[0]);
};
const submitPost = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("image", image);
dispatch(createPost(title, content, image));
};
return (
<div className="postCreate">
<h3 className="postCreate__heading">Create New Post</h3>
<div className="formBody">
<form onSubmit={submitPost}>
<div className="formInputs">
<label className="label">Title</label>
<input
className="titleInput"
type="text"
value={title}
onChange={(e) => setTile(e.target.value)}
placeholder="Enter the Title of the Post"
/>
</div>
<div className="formInputs">
<input type="file" onChange={fileOnChange} />
</div>
<div className="formInputs">
<label className="label">Content</label>
<textarea
className="titleInput"
type="text"
style={{
width: "1500px",
height: "500px",
color: "black",
outline: "none",
border: "none",
borderRadius: "6px",
}}
value={content}
onChange={(e) => setContent(e.target.value)}
/>
</div>
<div className="button">
<Button type="submit" variant="contained" color="primary">
Post
</Button>
</div>
{/* <button type="submit">Post</button> */}
</form>
Here is my action
export const createPost = (title, content, image) => async (dispatch) => {
try {
dispatch({ type: POST_POST_LOADING });
const config = { headers: { "Content-Type": "application/json" } };
const { data } = await axios.post(
"/api/newpost",
{ title, content },
config
);
dispatch({
type: POST_POST_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: POST_POST_FAIL,
payload: error,
});
}
};
Here is my postController
const createPost = async (req, res) => {
const { title, content, writer, comment, image } = req.body;
const fileType = req.file.mimetype.split("/")[1];
const newFileName = req.file.filename + "." + fileType;
fs.rename(
`uploads/images/${req.file.filename}`,
`uploads/images/${newFileName}`,
(req, res) => {
console.log("Renamed");
}
);
// const imageUrl = req.file.filename;
const newPost = await Post.create({
title,
content,
writer,
comment,
image,
// imageUrl,
});
if (newPost) {
res.send("Post created");
console.log("Post created");
} else {
res.status(201).send("Post not created");
console.log("Post not created");
}
};
Here is my routes
router.post("/newpost", upload.single("image"), createPost);
You're creating a form, which is a good start, but not sending it with axios.
To send a file from frontend to backend, you need to construct a form using FormData API and append the file to it. You can also append additional data to it.
Here is how I would change your code to work. In your form file:
const formData = new FormData();
formData.append('image', image);
formData.append('title', title);
formData.append('content', content);
dispatch(createPost(formData));
Then change your action to:
export const createPost = (formData) => async (dispatch) => {
try {
dispatch({ type: POST_POST_LOADING });
const config = { headers: { "Content-Type": "multipart/form-data" } };
const { data } = await axios.post(
"/api/newpost",
formData,
config
);
dispatch({
type: POST_POST_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: POST_POST_FAIL,
payload: error,
});
}
};

Failed to load resource : the server responded with status of 400

import React from 'react';
class Register extends React.Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
name: ''
}
}
onNameChange = (event) => {
this.setState({name: event.target.value})
}
onEmailChange = (event) => {
this.setState({email: event.target.value})
}
onPasswordChange = (event) => {
this.setState({password: event.target.value})
}
onSubmitSignIn = () => {
fetch('https://warm-earth-96837.herokuapp.com/register', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
email: this.state.email,
password: this.state.password,
name: this.state.name
})
})
.then(response => response.json())
.then(user => {
if (user.id) {
this.props.loadUser(user)
this.props.onRouteChange('home');
}
})
}
render() {
return (
<article className="br3 ba b--black-10 mv4 w-100 w-50-m w-25-l mw6 shadow-5 center">
<main className="pa4 black-80">
<div className="measure">
<fieldset id="sign_up" className="ba b--transparent ph0 mh0">
<legend className="f1 fw6 ph0 mh0">Register</legend>
<div className="mt3">
<label className="db fw6 lh-copy f6" htmlFor="name">Name</label>
<input
className="pa2 input-reset ba bg-transparent hover-bg-black hover-white w-100"
type="text"
name="name"
id="name"
onChange={this.onNameChange}
/>
</div>
<div className="mt3">
<label className="db fw6 lh-copy f6" htmlFor="email-address">Email</label>
<input
className="pa2 input-reset ba bg-transparent hover-bg-black hover-white w-100"
type="email"
name="email-address"
id="email-address"
onChange={this.onEmailChange}
/>
</div>
<div className="mv3">
<label className="db fw6 lh-copy f6" htmlFor="password">Password</label>
<input
className="b pa2 input-reset ba bg-transparent hover-bg-black hover-white w-100"
type="password"
name="password"
id="password"
onChange={this.onPasswordChange}
/>
</div>
</fieldset>
<div className="">
<input
onClick={this.onSubmitSignIn}
className="b ph3 pv2 input-reset ba b--black bg-transparent grow pointer f6 dib"
type="submit"
value="Register"
/>
</div>
</div>
</main>
</article>
);
}
}
export default Register;
server.js
const express = require('express');
const bodyParser = require('body-parser');
const bcrypt = require('bcrypt-nodejs');
const cors = require('cors');
const knex = require('knex');
const register = require('./controllers/register');
const signin = require('./controllers/signin');
const profile = require('./controllers/profile');
const image = require('./controllers/image');
const db = knex({
client: 'pg',
connection: {
connectionString : process.env.DATABASE_URL,
ssl : true,
}
});
const app = express();
app.use(cors())
app.use(bodyParser.json());
app.get('/', (req, res)=> { res.send('it is working!') })
app.post('/signin', signin.handleSignin(db, bcrypt))
app.post('/register', (req, res) => { register.handleRegister(req, res, db, bcrypt) })
app.get('/profile/:id', (req, res) => { profile.handleProfileGet(req, res, db)})
app.put('/image', (req, res) => { image.handleImage(req, res, db)})
app.post('/imageurl', (req, res) => { image.handleApiCall(req, res)})
app.listen(process.env.PORT || 3000, ()=> {
console.log(`app is running on port ${process.env.PORT}`);
})
App.js
import React, { Component } from 'react';
import Particles from 'react-particles-js';
import FaceRecognition from './components/FaceRecognition/FaceRecognition';
import Navigation from './components/Navigation/Navigation';
import Signin from './components/Signin/Signin';
import Register from './components/Register/Register';
import Logo from './components/Logo/Logo';
import ImageLinkForm from './components/ImageLinkForm/ImageLinkForm';
import Rank from './components/Rank/Rank';
import './App.css';
const particlesOptions = {
//customize this to your liking
particles: {
number: {
value: 30,
density: {
enable: true,
value_area: 800
}
}
}
}
const initialState = {
input: '',
imageUrl: '',
box: {},
route: 'signin',
isSignedIn: false,
user: {
id: '',
name: '',
email: '',
entries: 0,
joined: ''
}
}
class App extends Component {
constructor() {
super();
this.state = initialState;
}
loadUser = (data) => {
this.setState({user: {
id: data.id,
name: data.name,
email: data.email,
entries: data.entries,
joined: data.joined
}})
}
calculateFaceLocation = (data) => {
const clarifaiFace = data.outputs[0].data.regions[0].region_info.bounding_box;
const image = document.getElementById('inputimage');
const width = Number(image.width);
const height = Number(image.height);
return {
leftCol: clarifaiFace.left_col * width,
topRow: clarifaiFace.top_row * height,
rightCol: width - (clarifaiFace.right_col * width),
bottomRow: height - (clarifaiFace.bottom_row * height)
}
}
displayFaceBox = (box) => {
this.setState({box: box});
}
onInputChange = (event) => {
this.setState({input: event.target.value});
}
onButtonSubmit = () => {
this.setState({imageUrl: this.state.input});
fetch('https://warm-earth-96837.herokuapp.com/imageurl', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
input: this.state.input
})
})
.then(response => response.json())
.then(response => {
if (response) {
fetch('https://warm-earth-96837.herokuapp.com/image', {
method: 'put',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
id: this.state.user.id
})
})
.then(response => response.json())
.then(count => {
this.setState(Object.assign(this.state.user, { entries: count}))
})
.catch(console.log)
}
this.displayFaceBox(this.calculateFaceLocation(response))
})
.catch(err => console.log(err));
}
onRouteChange = (route) => {
if (route === 'signout') {
this.setState(initialState)
} else if (route === 'home') {
this.setState({isSignedIn: true})
}
this.setState({route: route});
}
render() {
const { isSignedIn, imageUrl, route, box } = this.state;
return (
<div className="App">
<Particles className='particles'
params={particlesOptions}
/>
<Navigation isSignedIn={isSignedIn} onRouteChange={this.onRouteChange} />
{ route === 'home'
? <div>
<Logo />
<Rank
name={this.state.user.name}
entries={this.state.user.entries}
/>
<ImageLinkForm
onInputChange={this.onInputChange}
onButtonSubmit={this.onButtonSubmit}
/>
<FaceRecognition box={box} imageUrl={imageUrl} />
</div>
: (
route === 'signin'
? <Signin loadUser={this.loadUser} onRouteChange={this.onRouteChange}/>
: <Register loadUser={this.loadUser} onRouteChange={this.onRouteChange}/>
)
}
</div>
);
}
}
export default App;
import React, { Component } from 'react';
import Particles from 'react-particles-js';
import FaceRecognition from './components/FaceRecognition/FaceRecognition';
import Navigation from './components/Navigation/Navigation';
import Signin from './components/Signin/Signin';
import Register from './components/Register/Register';
import Logo from './components/Logo/Logo';
import ImageLinkForm from './components/ImageLinkForm/ImageLinkForm';
import Rank from './components/Rank/Rank';
import './App.css';
const particlesOptions = {
//customize this to your liking
particles: {
number: {
value: 30,
density: {
enable: true,
value_area: 800
}
}
}
}
const initialState = {
input: '',
imageUrl: '',
box: {},
route: 'signin',
isSignedIn: false,
user: {
id: '',
name: '',
email: '',
entries: 0,
joined: ''
}
}
class App extends Component {
constructor() {
super();
this.state = initialState;
}
loadUser = (data) => {
this.setState({user: {
id: data.id,
name: data.name,
email: data.email,
entries: data.entries,
joined: data.joined
}})
}
calculateFaceLocation = (data) => {
const clarifaiFace = data.outputs[0].data.regions[0].region_info.bounding_box;
const image = document.getElementById('inputimage');
const width = Number(image.width);
const height = Number(image.height);
return {
leftCol: clarifaiFace.left_col * width,
topRow: clarifaiFace.top_row * height,
rightCol: width - (clarifaiFace.right_col * width),
bottomRow: height - (clarifaiFace.bottom_row * height)
}
}
displayFaceBox = (box) => {
this.setState({box: box});
}
onInputChange = (event) => {
this.setState({input: event.target.value});
}
onButtonSubmit = () => {
this.setState({imageUrl: this.state.input});
fetch('https://warm-earth-96837.herokuapp.com/imageurl', {
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
input: this.state.input
})
})
.then(response => response.json())
.then(response => {
if (response) {
fetch('https://warm-earth-96837.herokuapp.com/image', {
method: 'put',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
id: this.state.user.id
})
})
.then(response => response.json())
.then(count => {
this.setState(Object.assign(this.state.user, { entries: count}))
})
.catch(console.log)
}
this.displayFaceBox(this.calculateFaceLocation(response))
})
.catch(err => console.log(err));
}
onRouteChange = (route) => {
if (route === 'signout') {
this.setState(initialState)
} else if (route === 'home') {
this.setState({isSignedIn: true})
}
this.setState({route: route});
}
render() {
const { isSignedIn, imageUrl, route, box } = this.state;
return (
<div className="App">
<Particles className='particles'
params={particlesOptions}
/>
<Navigation isSignedIn={isSignedIn} onRouteChange={this.onRouteChange} />
{ route === 'home'
? <div>
<Logo />
<Rank
name={this.state.user.name}
entries={this.state.user.entries}
/>
<ImageLinkForm
onInputChange={this.onInputChange}
onButtonSubmit={this.onButtonSubmit}
/>
<FaceRecognition box={box} imageUrl={imageUrl} />
</div>
: (
route === 'signin'
? <Signin loadUser={this.loadUser} onRouteChange={this.onRouteChange}/>
: <Register loadUser={this.loadUser} onRouteChange={this.onRouteChange}/>
)
}
</div>
);
}
}
export default App;
Register Handler Code
const handleRegister = (req, res, db, bcrypt) => {
const { email, name, password } = req.body;
if (!email || !name || !password) {
return res.status(400).json('incorrect form submission');
}
const hash = bcrypt.hashSync(password);
db.transaction(trx => {
trx.insert({
hash: hash,
email: email
})
.into('login')
.returning('email')
.then(loginEmail => {
return trx('users')
.returning('*')
.insert({
email: loginEmail[0],
name: name,
joined: new Date()
})
.then(user => {
res.json(user[0]);
})
})
.then(trx.commit)
.catch(trx.rollback)
})
.catch(err => res.status(400).json('unable to register'))
}
module.exports = {
handleRegister: handleRegister
};
I am getting error 400 when i am trying to register a user.
Failed to load resource: the server responded with a status of 400 (Bad Request)
i have attached my register.js file
Register.js:26 POST https://warm-earth-96837.herokuapp.com/register 400 (Bad Request)
Register.onSubmitSignIn # Register.js:26
The 400 Bad Request Error is an HTTP response status code that indicates that the server was unable to process the request sent by the client due to invalid syntax. As with the dozens of potential HTTP response codes, receiving a 400 Bad Request Error while accessing your own application can be both frustrating and challenging to fix. Such HTTP response codes represent the complex relationship between the client, a web application, a web server, and often multiple third-party web services, so determining the cause of a particular status code can be a difficult, even within a controlled development environment
The 400 error happens when, for example, your route signup needs a field "name" and you did not send this field, or when you send a field that, for example, should be a string but you sent an Integer. That is, your request is wrong. Please put here what your route request to sign up the user so we can conclude what field is wrong or what is missing.
Thx and waiting for your response :).

Express server "failed to load resource: the server responded with a status of 500" after fetch request to server. How do I fix this error?

When a user enters their email and password then click login a fetch request is made to my server:
const RegistrationForm = (props) => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const handleLoginSuccess = (props) => {
return props.history.push("./homepage");
};
const handleSubmit = (e) => {
e.preventDefault();
authApiService
.userLogin({ email, password })
.then((res) => {
password.value = "";
TokenService.saveAuthToken(res.authToken);
handleLoginSuccess();
})
.catch((res) => {
console.log(res.error);
});
};
return (
<form onSubmit={handleSubmit}>
<fieldset>
<div className="form-group">
<div>
<label htmlFor="registration-email">Email</label>
</div>
<EmailInput
value={email}
handleChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className="form-group">
<div>
<label htmlFor="registration-password">Password</label>
</div>
<PasswordInput
value={password}
handleChange={(e) => setPassword(e.target.value)}
/>
</div>
</fieldset>
<Button type="submit" theme="registration-button">
Log in
</Button>
<ul>
<li>
<Link to="/register-account">Create account</Link>
</li>
</ul>
</form>
);
};
Fetch request is made here:
userLogin({ email, password }) {
return fetch(`${config.API_ENDPOINT}/auth/login`, {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({ email, password }),
})
.then((res) => {
!res.ok ? res.json().then((e) => Promise.reject(e)) : res.json();
})
.then((res) => {
TokenService.saveAuthToken(res.authToken);
IdleService.registerIdleTimerResets();
TokenService.queueCallbackBeforeExpiry(() => {
authApiService.postRefreshToken();
});
return res;
});
},
postRefreshToken() {
return fetch(`${config.API_ENDPOINT}/auth/refresh`, {
method: "POST",
headers: {
authorization: `Bearer ${TokenService.getAuthToken()}`,
},
})
.then((res) =>
!res.ok ? res.json().then((e) => Promise.reject(e)) : res.json()
)
.then((res) => {
TokenService.saveAuthToken(res.authToken);
TokenService.queueCallbackBeforeExpiry(() => {
authApiService.postRefreshToken();
});
return res;
})
.catch((err) => {
console.log("refresh token req error");
console.log(err);
});
},
Then on the server this is the route for this request:
authRouter.post("/login", jsonBodyParser, (req, res, next) => {
const { email, password } = req.body;
const userLoggingIn = { email, password };
for (const [key, value] of Object.entries(userLoggingIn))
if (value == null)
return res
.status(400)
.json({ error: `Missing '${key}' in request body` });
authService
.confirmUserNameExists(req.app.get("db"), userLoggingIn.email)
.then((userInDb) => {
if (!userInDb)
return res
.status(400)
.json({ error: "Incorrect email or password" });
});
return authService
.comparePasswords(userLoggingIn.password, userInDb.password)
.then((matchedPw) => {
if (!matchedPw)
return res
.status(400)
.json({ error: "Incorrect email or password" });
const subject = userInDb.email;
const payload = { userId: userInDb.id };
res.send({ authToken: authService.createJwt(subject, payload) });
})
.catch(next);
});
authRouter.post("/refresh", requiresAuthorization, (req, res) => {
const subject = req.user.email;
const payload = { userId: req.user.id };
res.send({
authToken: authService.createJwt(subject, payload),
});
});
Im getting the error in the title (500 error, failed to load resource and its pointing to the fetch request. I've tried googling and looking on stack overflow for hours and can't figure it out. Any help would be greatly appreciated. The goal is just to get the user logged in, redirect the user to the home page, create a JWT and store it.

Resources