I am building a nodejs, reactjs app and i am having issues for making requests from my reactjs part of the app to my API. I am using concurrently, so i made a proxy:
"proxy":"http://localhost:5000/"
Port 5000 is where my API is running and Port 3000 is where my ReactJs runs.
When i try to register a new user i get the following error
Cannot POST api/users
And my console shows what url is trying to request http://localhost:3000/api/users
But instead it should be http://localhost:5000/api/users
This is my Register.js:
import React, { Fragment, useState } from 'react'
import axios, { Axios } from 'axios';
const Register = () => {
const [formData, setFormData] = useState({
name:'',
email: '',
password: '',
password2: ''
});
const { name, email, password, password2 } = formData;
const onChange = e => setFormData({
...formData, [e.target.name]:e.target.value
});
const onSubmit = async e => {
e.preventDefault();
if(password !== password2){
console.log('Passwords do not match')
} else {
const newUser = {
name,
email,
password
}
try {
const config = {
headers:{
'Content-type': 'application/json'
}
}
const body = JSON.stringify(newUser)
const res = await axios.post('api/users', body, config);
console.log(res.data);
} catch (error) {
console.error(error.response.data)
}
}
}
return (
<Fragment>
<section className='container'>
<h1 className="large text-primary">Sign Up</h1>
<p className="lead"><i className="fas fa-user"></i> Create Your Account</p>
<form className="form" action="create-profile.html" onSubmit={e => onSubmit(e)}>
<div className="form-group">
<input type="text"
placeholder="Name"
name="name"
value={name}
onChange={e => onChange(e)}
required />
</div>
<div className="form-group">
<input type="email"
placeholder="Email Address"
name="email" value={email}
onChange={e => onChange(e)}
required/>
<small className="form-text"
>This site uses Gravatar so if you want a profile image, use a
Gravatar email</small
>
</div>
<div className="form-group">
<input
type="password"
placeholder="Password"
name="password"
minLength="6"
value={password}
onChange={e => onChange(e)}
required
/>
</div>
<div className="form-group">
<input
type="password"
placeholder="Confirm Password"
name="password2"
minLength="6"
value={password2}
onChange={e => onChange(e)}
required
/>
</div>
<input type="submit" className="btn btn-primary" value="Register" />
</form>
<p className="my-1">
Already have an account? Sign In
</p>
</section>
</Fragment>
)
}
export default Register
And this is my users.js
//#route POST api/users
//#desc Register user
//#access public
router.post('/', [
check('name', 'Name is required')
.not()
.isEmpty(),
check('email', 'Plese include a valid email').isEmail(),
check('password', 'Please enter a password with 6 or more characters').isLength({min:6})
],
async (req, res)=> {
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({ errors:errors.array()}); //400 is for bad requests
}
const { name, email, password } = req.body;
try{
//See if user exists
let user = await User.findOne({ email });
if(user){
return res.status(400).json({ errors: [{ msg:'User already exists' }] });
}
//Get users gravatar
const avatar = gravatar.url(email,{
s:'200',
r:'pg',
d:'mm'
})
user = new User({
name,
email,
avatar,
password
});
//Encrypt password
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
//Return jsonwebtoken -> this for users to be logged in right after registration
const payload = {
user:{
id: user.id
}
}
jwt.sign(
payload,
config.get('jwtSecret'),
{expiresIn: 360000}, //change to 3600 for production
(err, token)=>{
if(err) throw err;
res.json({ token });
}
)
}catch(err){
console.error('err.message');
res.status(500).send('Server Error');
}
});
module.exports = router;
What am i doing wrong? What is the solution to this error?
Related
I want to use my own API to check the information about email and password, but I don't know how to do that. Anything information that I put show up "Login" but I need to just show up "Login" if the information was the same that I registered in my database.
import { useState } from 'react';
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
import { Link } from "react-router-dom"
const Login = () => {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const handleSubmit = (e) => {
e.preventDefault()
const info = {email, password}
fetch('http://localhost:3333/login/', {
mode: 'no-cors',
method: 'POST',
headers: { "Content-Type": "application/json" },
body: JSON.stringify(info)
}).then((response) => {
console.log(response)
console.log("login")
}).catch(() => {
console.log("NO")
})
}
return (
<div className="all ">
<div className='button d-flex justify-content-center '>
<Link to="/" className="text-center btn btn-secondary btn-lg m-4">Login</Link>
<Link to="/register" className="text-center btn btn-secondary btn-lg m-4">Register</Link>
</div>
<p className='text-center'>Sign With:</p>
<div className="container d-flex justify-content-center">
<Form onSubmit={handleSubmit}>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email" value = {email} onChange={(e) => setEmail (e.target.value)} placeholder="Enter email" required/>
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" value = {password} onChange={e => setPassword(e.target.value)} placeholder="Password" />
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicCheckbox">
<Form.Check type="checkbox" label="Check me out" />
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</div>
</div>
);
}
export default Login;
My API is shown below and it's working fine and the login function is verifying well
const {
PrismaClient
} = require("#prisma/client");
const prisma = new PrismaClient();
const bcrypt = require('bcrypt');
module.exports = {
async createUser(req, res) {
try {
const {
firstName,
lastName,
email,
password,
age,
role
} = req.body
const salt = await bcrypt.genSalt();
console.log(salt)
const hash = await bcrypt.hash(password, salt)
console.log(hash)
const verifyemail = await prisma.UserInfo.findUnique({
where: {
email
}
})
if (verifyemail) {
return res.json({
error: "there is a email with the same name, please change."
})
}
const user = await prisma.UserInfo.create({
data: {
firstName: firstName,
lastName: lastName,
email: email,
password: hash,
age: age,
role: role
}
});
return res.json(user)
} catch (error) {
return res.json({
error
})
}
},
async login(req, res) {
try {
const {email, password} = req.body
const user = await prisma.UserInfo.findUnique({
where: {
email : req.body.email
}
})
if(user) {
const match = await bcrypt.compare(password, user.password)
if(match) {
return res.send("login")
}
else {
return res.send("There is something wrong with your password")
}
}
} catch (error) {
return res.json({
error
})
}
}
}
What I have understood from your question is that, no matter what username and password you are entering you are always ending up in the .then block, while if the username/password is wrong it should go to the catch block.
If I have understood that correctly, I would suggest updating your node code to handle this scenario. Fetch will only go in catch if there is a network error or CORS error, check this
With this, I would suggest you can add an else block in your Node code and add
return res.status(401).send("Icorrect password");
after this, in front end code, you can add
.then(response => /* check response status code and throw 'Incorrect' if 401 */ )
I am devloping a webapp with nodejs and reactjs with redux. I am trying to make a request to register a new user but i am getting a bad request.
This is the error i am getting:
POST http://localhost:5000/api/users 400 bad request
This is my users route:
const express = require('express');
const config = require('config');
const router = express.Router();
const gravatar = require('gravatar');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { check , validationResult } = require('express-validator/');
const User = require('../../models/User');
//#route POST api/users
//#desc Register user
//#access public
router.post('/', [
check('name', 'Name is required')
.not()
.isEmpty(),
check('email', 'Plese include a valid email').isEmail(),
check('password', 'Please enter a password with 6 or more characters').isLength({min:6})
],
async (req, res)=> {
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({ errors:errors.array()}); //400 is for bad requests
}
const { name, email, password } = req.body;
try{
//See if user exists
let user = await User.findOne({ email });
if(user){
return res.status(400).json({ errors: [{ msg:'User already exists' }] });
}
//Get users gravatar
const avatar = gravatar.url(email,{
s:'200',
r:'pg',
d:'mm'
})
user = new User({
name,
email,
avatar,
password
});
//Encrypt password
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
//Return jsonwebtoken -> this for users to be logged in right after registration
const payload = {
user:{
id: user.id
}
}
jwt.sign(
payload,
config.get('jwtSecret'),
{expiresIn: 360000}, //change to 3600 for production
(err, token)=>{
if(err) throw err;
res.json({ token });
}
)
}catch(err){
console.error('err.message');
res.status(500).send('Server Error');
}
});
module.exports = router;
The route is not the problem i think because if i register manually a user via postman it works.
This is my register.js component:
import React, { useState } from 'react';
import { connect } from 'react-redux';
import { Link, Navigate } from 'react-router-dom';
import { setAlert } from '../../actions/alert';
import { register } from '../../actions/auth';
import PropTypes from 'prop-types';
const Register = ({ setAlert, register }) => {
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
password2: ''
});
const { name, email, password, password2 } = formData;
const onChange = (e) =>
setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = async (e) => {
e.preventDefault();
if (password !== password2) {
setAlert('Passwords do not match', 'danger');
} else {
register({ name, email, password });
console.log('SUCCESS')
}
};
return (
<section className="container">
<h1 className="large text-primary">Sign Up</h1>
<p className="lead">
<i className="fas fa-user" /> Create Your Account
</p>
<form className="form" onSubmit={onSubmit}>
<div className="form-group">
<input
type="text"
placeholder="Name"
name="name"
value={name}
onChange={onChange}
/>
</div>
<div className="form-group">
<input
type="email"
placeholder="Email Address"
name="email"
value={email}
onChange={onChange}
/>
<small className="form-text">
This site uses Gravatar so if you want a profile image, use a
Gravatar email
</small>
</div>
<div className="form-group">
<input
type="password"
placeholder="Password"
name="password"
value={password}
onChange={onChange}
/>
</div>
<div className="form-group">
<input
type="password"
placeholder="Confirm Password"
name="password2"
value={password2}
onChange={onChange}
/>
</div>
<input type="submit" className="btn btn-primary" value="Register" />
</form>
<p className="my-1">
Already have an account? <Link to="/login">Sign In</Link>
</p>
</section>
);
};
Register.propTypes = {
setAlert: PropTypes.func.isRequired,
register: PropTypes.func.isRequired
};
export default connect( null, { setAlert , register })(Register);
and this is one of my actions auth.js where i request my api
import axios from "axios";
import { setAlert } from './alert'
import {
REGISTER_SUCCESS,
REGISTER_FAIL
} from './types'
//Register user
export const register = ( { name, email, password } ) => async dispatch => {
const config = {
headers: {
'Content-type': 'application/json'
}
}
const body = JSON.stringify({ name , email, password });
try {
const res = await axios.post('http://localhost:5000/api/users', body, config);
dispatch({
type: REGISTER_SUCCESS,
payload: res.data
});
} catch (error) {
const errors = error.response.data.errors;
if(errors){
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type:REGISTER_FAIL
});
}
}
I am pretty sure this might be an axios error on how i am trying to perform a request or a redux mistake.
My app works fine, if i donĀ“t enter or enter invalid data to my registration form all my validation alerts show up. The issue is when i submit the form and try to send the data to register the new user.
I am working on a project , first i did user signup and login based on jwt authentication * note i am using reactjs * i want to disallow users from logging in several time from different tabs or browsers , what shall i do ? how to implement such service and where? i will provide the whol code that may be helpful
i want some one to help me implement not just give me the logic
This is my main express file :
//the main framework , express
var express = require('express');
//path , used for joining pathes
var path = require('path');
//cross origin resource sharing
var cors= require('cors')
//body parser used to take data from forms , to be used later on
var bodyParser=require("body-parser");
//for security reasons , http security(not https)
var helmet= require('helmet')
//for parsing tokens and session cookies
var cookieParser= require('cookie-parser')
//assigning express functionaities as a global variable
const app = express()
//assigning cors functionaities as a global variable
app.use(cors())
//headers that will be sent to the browser
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader('Access-Control-Allow-Methods', ['PATCH', 'POST', 'GET', 'DELETE', 'PUT']);
res.setHeader('Access-Control-Allow-Headers' , '*')
res.setHeader('Access-Control-Expose-Headers' ,'content-type')
next();
});
//body parser for form data
app.use(bodyParser.json())
app.use(bodyParser.json({ type: 'application/json' }))
app.use(bodyParser.urlencoded({ extended: true }))
app.use(cookieParser())
// secure apps by setting various HTTP headers
app.use(helmet())
// enable CORS - Cross Origin Resource Sharing
app.options('*', cors());
//fetching index from react
app.use(express.static('./build/'));
app.use(express.static(path.join(__dirname, './client/build')));
app.get('*', (req, res) => {
res.send(express.static(path.join(__dirname, './client/build/index.html'))) ;
});
//giving the functionalities of users.js to a variable users to be used later on
var Users = require('./routes/Users')
//using the functions assigned for users
app.use('/users', Users)
//exporting the app file
module.exports = app
this is the routes file which contains my controller:
const express = require('express')
//setting a users variable to be used as a router instead of app post , get ..
const users = express.Router()
//cross oigin resource sharing
const cors = require('cors')
//jwt for user login authentication
const jwt = require('jsonwebtoken')
//bcrypt for password encryption and decryption
const bcrypt = require('bcrypt')
//using te user model
const User = require('../model/user')
//setting users as cros origin functionalities
users.use(cors())
//privat key or jwt encryption and decryption
process.env.SECRET_KEY = 'q1w2e3r4t5y6u7i8o9p0o9i8u7y6t5r4e3w2q1'
//main signup function , exported
users.post('/signup', (req, res) => {
//setting a new user object to be manipulated and inserted to db
//data taken from react client side
const today = new Date()
const userData = {
username : req.body.username,
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: req.body.password,
created: today
}
//a function from sequelize , a wrapper for later on functions
//searches if the username is found or not
User.findOne({
where: {
//searching in the whhole db for this user name
username: req.body.username
}
})
// encrypting the password using bcrypt encryption function
//bcrypt uses a hash function to encrypt the user given password
//will not reach this part if user is duplicated
.then(user => {
if (!user) {
//hashing the password , 10 is a number for permutations 2pwr10 = a certain string built in
bcrypt.hash(req.body.password, 10, (err, hash) => {
userData.password = hash
//creating a user with the given data
User.create(userData)
//send the username to the response tab in console
.then(user => {
res.json({ status: user.username + ' '+ 'Registered!' })
})
//any error will be consoled here
.catch(err => {
res.send('error: ' + err)
})
})
} else {
//will reach if username is found , User.findOne
res.json({ error: 'User already exists' })
}
})
.catch(err => {
res.send('error: ' + err)
})
})
//main login functionality
users.post('/login', (req, res) => {
///searches for username in db at first
User.findOne({
where: {
username: req.body.username
}
})
//if the user is found , it compared the password with the given password
//it compared it the encrypted pass in the db
//and decrypts it to compare
.then(user => {
if (user) {
//if user name is found the deryption starts here
if (bcrypt.compareSync(req.body.password, user.password)) {
//each user is given a certain jwt token for authentication
//jwt.sign , Synchronously sign the given payload into a JSON Web Token string payload
//secret key provided above
//token is assigned using the front end whuck sends it with the request
let token = jwt.sign(user.dataValues, process.env.SECRET_KEY, {
expiresIn: 1440
})
//send token to local storage of the browser that checks it
res.send(token)
}
} else {
//reaches here if user isnt found
res.status(400).json({ error: 'User does not exist' })
}
})
//catches any error from the above blocks
.catch(err => {
res.status(400).json({ error: err })
})
})
users.get('/profile', (req, res) => {
//Synchronously verify given token using a secret or a public key to get a decoded token token -
// JWT string to verify secretOrPublicKey - Either the secret for HMAC algorithms,
//or the PEM encoded public key for RSA and ECDSA.
// [options] - Options for the verification returns - The decoded token.
var decoded = jwt.verify(req.headers['authorization'], process.env.SECRET_KEY)
//searches for user
User.findOne({
//decode user id and jwt
where: {
id: decoded.id
}
})
//if true, user is sent as a json object to browser
.then(user => {
if (user) {
console.log(user)
res.json(user)
} else {
//if false , send this response
res.send('User does not exist')
}
})
.catch(err => {
res.send('error: ' + err)
})
})
module.exports = users
react front end end-points:
import axios from 'axios'
import jwt_decode from 'jwt-decode'
//the signup endpoint sent from front end and interpreted by the browser
//route is an api called users , exported from server side
//posting user data as in server
//sending a response if true
export const signup = newUser => {
return axios
.post('users/signup', {
username : newUser.username,
first_name: newUser.first_name,
last_name: newUser.last_name,
email: newUser.email,
password: newUser.password
})
.then(response => {
console.log('Registered')
})
}
//login end point
//using username and password , using the decoded id
export const login = async user => {
try {
const response = await axios
.post('users/login', {
username: user.username,
password: user.password
});
localStorage.setItem('usertoken', response.data);
return response.data;
}
catch (err) {
console.log(err);
}
}
Login react page
import React, { Component } from 'react'
import { withRouter} from 'react-router-dom';
import { login } from './api-user'
class Login extends Component {
constructor() {
super()
this.state = {
username: '',
password: '',
errors: {}
}
this.onChange = this.onChange.bind(this)
this.onSubmit = this.onSubmit.bind(this)
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value })
}
// parseJwt(token) {
// if (!token) { return; }
// const base64Url = token.split('.')[1];
// const base64 = base64Url.replace('-', '+').replace('_', '/');
// return JSON.parse(window.atob(base64));
// }
onSubmit(e) {
e.preventDefault()
const user = {
username:this.state.username,
password: this.state.password
}
login(user).then(res => {
if (res) {
this.props.history.push(`/profile`)
}
})
localStorage.setItem('username',
JSON.stringify(this.state.username))
}
render() {
return (
<div className="container">
<div className="row">
<div className="col-md-6 mt-5 mx-auto">
<form noValidate onSubmit={this.onSubmit}>
<h1 className="h3 mb-3 font-weight-normal">Please sign in</h1>
<div className="form-group">
<label htmlFor="text">Username</label>
<input
type="text"
className="form-control"
name="username"
placeholder="Enter username"
value={this.state.username}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
type="password"
className="form-control"
name="password"
placeholder="Password"
value={this.state.password}
onChange={this.onChange}
/>
</div>
<button
type="submit"
className="btn btn-lg btn-primary btn-block"
>
Sign in
</button>
</form>
</div>
</div>
</div>
)
}
}
signup react page
mport React, { Component } from 'react'
import { signup } from './api-user'
class SignUp extends Component {
constructor() {
super()
this.state = {
username:'',
first_name: '',
last_name: '',
email: '',
password: '',
errors: {}
}
this.onChange = this.onChange.bind(this)
this.onSubmit = this.onSubmit.bind(this)
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value })
}
onSubmit(e) {
e.preventDefault()
const newUser = {
username: this.state.username,
first_name: this.state.first_name,
last_name: this.state.last_name,
email: this.state.email,
password: this.state.password
}
signup(newUser).then(res => {
this.props.history.push(`/login`)
})
}
render() {
return (
<div className="container">
<div className="row">
<div className="col-md-6 mt-5 mx-auto">
<form noValidate onSubmit={this.onSubmit}>
<h1 className="h3 mb-3 font-weight-normal">Register</h1>
<div className="form-group">
<label htmlFor="username">User Name</label>
<input
type="text"
className="form-control"
name="username"
placeholder="Enter your username"
value={this.state.username}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="first_name">First name</label>
<input
type="text"
className="form-control"
name="first_name"
placeholder="Enter your first name"
value={this.state.first_name}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="last_name">Last name</label>
<input
type="text"
className="form-control"
name="last_name"
placeholder="Enter your lastname name"
value={this.state.last_name}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="email">Email address</label>
<input
type="email"
className="form-control"
name="email"
placeholder="Enter email"
value={this.state.email}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
type="password"
className="form-control"
name="password"
placeholder="Password"
value={this.state.password}
onChange={this.onChange}
/>
</div>
<button
type="submit"
className="btn btn-lg btn-primary btn-block"
>
Register!
</button>
</form>
</div>
</div>
</div>
)
}
}
export default SignUp
please i asked this question before but no one helped me , some fellows gave me the logic but without the ode , i really in need of some code , what should i do ? new table to record signins ? how to connect my already found user table and if i want a new access_token table ? or should i do a flag in user table that changes (i dont know how , i just have the ideas )
From what I understand from your question is that you don't want your user to open the login page or the signup page if they are already signed in.
If thats the problem then a simple solution is to redirect the user to homepage/dashboard whenever they try to login if they are already authenticated.
<Route
exact path='/login'
render={props => this.state.isAuth ? <Redirect to='/dashboard' /> : <Login />}
/>
I am working on a project , first i did user signup and login based on jwt authentication * note i am using reactjs * i want to disallow users from logging in several time from different tabs or browsers , what shall i do ? how to implement such service and where? i will provide the whol code that may be helpful
This is my main express file :
//the main framework , express
var express = require('express');
//path , used for joining pathes
var path = require('path');
//cross origin resource sharing
var cors= require('cors')
//body parser used to take data from forms , to be used later on
var bodyParser=require("body-parser");
//for security reasons , http security(not https)
var helmet= require('helmet')
//for parsing tokens and session cookies
var cookieParser= require('cookie-parser')
//assigning express functionaities as a global variable
const app = express()
//assigning cors functionaities as a global variable
app.use(cors())
//headers that will be sent to the browser
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', true);
res.setHeader('Access-Control-Allow-Methods', ['PATCH', 'POST', 'GET', 'DELETE', 'PUT']);
res.setHeader('Access-Control-Allow-Headers' , '*')
res.setHeader('Access-Control-Expose-Headers' ,'content-type')
next();
});
//body parser for form data
app.use(bodyParser.json())
app.use(bodyParser.json({ type: 'application/json' }))
app.use(bodyParser.urlencoded({ extended: true }))
app.use(cookieParser())
// secure apps by setting various HTTP headers
app.use(helmet())
// enable CORS - Cross Origin Resource Sharing
app.options('*', cors());
//fetching index from react
app.use(express.static('./build/'));
app.use(express.static(path.join(__dirname, './client/build')));
app.get('*', (req, res) => {
res.send(express.static(path.join(__dirname, './client/build/index.html'))) ;
});
//giving the functionalities of users.js to a variable users to be used later on
var Users = require('./routes/Users')
//using the functions assigned for users
app.use('/users', Users)
//exporting the app file
module.exports = app
this is the routes file which contains my controller:
const express = require('express')
//setting a users variable to be used as a router instead of app post , get ..
const users = express.Router()
//cross oigin resource sharing
const cors = require('cors')
//jwt for user login authentication
const jwt = require('jsonwebtoken')
//bcrypt for password encryption and decryption
const bcrypt = require('bcrypt')
//using te user model
const User = require('../model/user')
//setting users as cros origin functionalities
users.use(cors())
//privat key or jwt encryption and decryption
process.env.SECRET_KEY = 'q1w2e3r4t5y6u7i8o9p0o9i8u7y6t5r4e3w2q1'
//main signup function , exported
users.post('/signup', (req, res) => {
//setting a new user object to be manipulated and inserted to db
//data taken from react client side
const today = new Date()
const userData = {
username : req.body.username,
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: req.body.password,
created: today
}
//a function from sequelize , a wrapper for later on functions
//searches if the username is found or not
User.findOne({
where: {
//searching in the whhole db for this user name
username: req.body.username
}
})
// encrypting the password using bcrypt encryption function
//bcrypt uses a hash function to encrypt the user given password
//will not reach this part if user is duplicated
.then(user => {
if (!user) {
//hashing the password , 10 is a number for permutations 2pwr10 = a certain string built in
bcrypt.hash(req.body.password, 10, (err, hash) => {
userData.password = hash
//creating a user with the given data
User.create(userData)
//send the username to the response tab in console
.then(user => {
res.json({ status: user.username + ' '+ 'Registered!' })
})
//any error will be consoled here
.catch(err => {
res.send('error: ' + err)
})
})
} else {
//will reach if username is found , User.findOne
res.json({ error: 'User already exists' })
}
})
.catch(err => {
res.send('error: ' + err)
})
})
//main login functionality
users.post('/login', (req, res) => {
///searches for username in db at first
User.findOne({
where: {
username: req.body.username
}
})
//if the user is found , it compared the password with the given password
//it compared it the encrypted pass in the db
//and decrypts it to compare
.then(user => {
if (user) {
//if user name is found the deryption starts here
if (bcrypt.compareSync(req.body.password, user.password)) {
//each user is given a certain jwt token for authentication
//jwt.sign , Synchronously sign the given payload into a JSON Web Token string payload
//secret key provided above
//token is assigned using the front end whuck sends it with the request
let token = jwt.sign(user.dataValues, process.env.SECRET_KEY, {
expiresIn: 1440
})
//send token to local storage of the browser that checks it
res.send(token)
}
} else {
//reaches here if user isnt found
res.status(400).json({ error: 'User does not exist' })
}
})
//catches any error from the above blocks
.catch(err => {
res.status(400).json({ error: err })
})
})
users.get('/profile', (req, res) => {
//Synchronously verify given token using a secret or a public key to get a decoded token token -
// JWT string to verify secretOrPublicKey - Either the secret for HMAC algorithms,
//or the PEM encoded public key for RSA and ECDSA.
// [options] - Options for the verification returns - The decoded token.
var decoded = jwt.verify(req.headers['authorization'], process.env.SECRET_KEY)
//searches for user
User.findOne({
//decode user id and jwt
where: {
id: decoded.id
}
})
//if true, user is sent as a json object to browser
.then(user => {
if (user) {
console.log(user)
res.json(user)
} else {
//if false , send this response
res.send('User does not exist')
}
})
.catch(err => {
res.send('error: ' + err)
})
})
module.exports = users
react front end end-points:
import axios from 'axios'
import jwt_decode from 'jwt-decode'
//the signup endpoint sent from front end and interpreted by the browser
//route is an api called users , exported from server side
//posting user data as in server
//sending a response if true
export const signup = newUser => {
return axios
.post('users/signup', {
username : newUser.username,
first_name: newUser.first_name,
last_name: newUser.last_name,
email: newUser.email,
password: newUser.password
})
.then(response => {
console.log('Registered')
})
}
//login end point
//using username and password , using the decoded id
export const login = async user => {
try {
const response = await axios
.post('users/login', {
username: user.username,
password: user.password
});
localStorage.setItem('usertoken', response.data);
return response.data;
}
catch (err) {
console.log(err);
}
}
Login react page:
import React, { Component } from 'react'
import { withRouter} from 'react-router-dom';
import { login } from './api-user'
class Login extends Component {
constructor() {
super()
this.state = {
username: '',
password: '',
errors: {}
}
this.onChange = this.onChange.bind(this)
this.onSubmit = this.onSubmit.bind(this)
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value })
}
// parseJwt(token) {
// if (!token) { return; }
// const base64Url = token.split('.')[1];
// const base64 = base64Url.replace('-', '+').replace('_', '/');
// return JSON.parse(window.atob(base64));
// }
onSubmit(e) {
e.preventDefault()
const user = {
username:this.state.username,
password: this.state.password
}
login(user).then(res => {
if (res) {
this.props.history.push(`/profile`)
}
})
localStorage.setItem('username',
JSON.stringify(this.state.username))
}
render() {
return (
<div className="container">
<div className="row">
<div className="col-md-6 mt-5 mx-auto">
<form noValidate onSubmit={this.onSubmit}>
<h1 className="h3 mb-3 font-weight-normal">Please sign in</h1>
<div className="form-group">
<label htmlFor="text">Username</label>
<input
type="text"
className="form-control"
name="username"
placeholder="Enter username"
value={this.state.username}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
type="password"
className="form-control"
name="password"
placeholder="Password"
value={this.state.password}
onChange={this.onChange}
/>
</div>
<button
type="submit"
className="btn btn-lg btn-primary btn-block"
>
Sign in
</button>
</form>
</div>
</div>
</div>
)
}
}
export default withRouter(Login);
signup react page
mport React, { Component } from 'react'
import { signup } from './api-user'
class SignUp extends Component {
constructor() {
super()
this.state = {
username:'',
first_name: '',
last_name: '',
email: '',
password: '',
errors: {}
}
this.onChange = this.onChange.bind(this)
this.onSubmit = this.onSubmit.bind(this)
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value })
}
onSubmit(e) {
e.preventDefault()
const newUser = {
username: this.state.username,
first_name: this.state.first_name,
last_name: this.state.last_name,
email: this.state.email,
password: this.state.password
}
signup(newUser).then(res => {
this.props.history.push(`/login`)
})
}
render() {
return (
<div className="container">
<div className="row">
<div className="col-md-6 mt-5 mx-auto">
<form noValidate onSubmit={this.onSubmit}>
<h1 className="h3 mb-3 font-weight-normal">Register</h1>
<div className="form-group">
<label htmlFor="username">User Name</label>
<input
type="text"
className="form-control"
name="username"
placeholder="Enter your username"
value={this.state.username}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="first_name">First name</label>
<input
type="text"
className="form-control"
name="first_name"
placeholder="Enter your first name"
value={this.state.first_name}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="last_name">Last name</label>
<input
type="text"
className="form-control"
name="last_name"
placeholder="Enter your lastname name"
value={this.state.last_name}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="email">Email address</label>
<input
type="email"
className="form-control"
name="email"
placeholder="Enter email"
value={this.state.email}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
type="password"
className="form-control"
name="password"
placeholder="Password"
value={this.state.password}
onChange={this.onChange}
/>
</div>
<button
type="submit"
className="btn btn-lg btn-primary btn-block"
>
Register!
</button>
</form>
</div>
</div>
</div>
)
}
}
export default SignUp
App.js main routing file
import React, { Component } from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import Landing from './components/user/Landing'
import Login from './components/user/Login'
import SignUp from './components/user/Signup'
import Profile from './components/user/Profile'
class App extends Component {
render() {
return (
<Router>
<div className="App">
<Route exact path="/landing" component={Landing} />
<Route exact path="/" component={Login} />
<div className="container">
<Route exact path="/signup" component={SignUp} />
<Route exact path="/profile" component={Profile} />
</div>
</div>
</Router>
)
}
}
export default App
Im not sure about how much of a scope you expect as an answer for this question but assuming you need the React solution, this is the basic approach you can take in your situation.
You can check for the availability of usertoken you store in localStorage at the login (since it is your root route) and do what is necessary (Redirect to the profile page maybe);
As an example,
// Use this lifecycle hook to check for the token before doing anything else
componentDidMount() {
const token = localStorage.getItem('usertoken');
if (token) this.props.history.push(`/profile`);
}
Although this will not work for multiple browsers. For that, you will have to manage a session from the server side.
If you want user can login with single device at time then you have manage the jwt token in database.
Suppose first time a user login with a device A then save token in database and send to token in api for front use.Now same user login with device B then user will login successful but put old token which is from device A in blacklist in jwt and database too. When device A user will hit any api then you have to check this user token is expired or in blacklist then you can clear localstorage redirect to login page.
Instead of multiple devices, this scenario will work for multiple browsers and multiple window of browsers.
You have to use only one pair "access_token"/"refresh_token" for each user. If the user will log in on another tab (browser... client...), your server side should disable exist tokens (access+refresh) for that user.
I have created a react client and sending my register form request to node server but I am getting the following error in my console while clicking the register button.
"POST http://localhost:3000/users/register 404 (Not Found)"
Please suggest a solution to it?
../routes/User.js
const users = express.Router()
const cors = require('cors')
const jwt = require("jsonwebtoken")
const bcrypt = require('bcrypt')
const User = require("../models/User")
users.use(cors())
process.env.SECRET_KEY = 'secret'
users.post('/register', (req, res) => {
const today = new Date()
const userData = {
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: req.body.password,
created: today
}
User.findOne({
where: {
email: req.body.email
}
})
.then(user => {
if(!user){
bcrypt.hash(req.body.password, 10, (err, hash) => {
userData.password = hash
User.create(userData)
.then(user => {
res.json({status: user.email + ' registered'})
})
.catch(err => {
res.send('error: ' + err)
})
})
} else {
res.json({error: "User already exists"})
}
})
.catch(err => {
res.send('error: ' + err)
})
})
users.post('/login', (req, res) => {
User.findOne({
where: {
email: req.body.email
}
})
.then(user => {
if(user) {
if(bcrypt.compareSync(req.body.password, user.password)) {
let token = jwt.sign(user.dataValues, process.env.SECRET_KEY, {
expiresin: 1440
})
res.send(token)
}
} else {
res.status(400).json({error: 'User does not exist'})
}
})
.catch(err => {
res.status(400).json({ error: err})
})
})
module.exports = users
../client/App.js
import './App.css';
import {BrowserRouter as Router, Route} from 'react-router-dom'
import Navbar from './components/Navbar'
import Landing from './components/Landing'
import Login from './components/Login'
import Register from './components/Register'
import Profile from './components/Profile'
function App() {
return (
<Router>
<div className="App">
<Navbar />
<Route exact path="/" component={Landing} />
<div className="container">
<Route exact path="/register" component={Register} />
<Route exact path="/login" component={Login} />
<Route exact path="/profile" component={Profile} />
</div>
</div>
</Router>
);
}
export default App;
../client/src/Register.js
import { register } from './UserFunctions'
class Register extends Component {
constructor() {
super()
this.state = {
first_name: '',
last_name: '',
email: '',
password: ''
}
this.onChange = this.onChange.bind(this)
this.onSubmit = this.onSubmit.bind(this)
}
onChange(e){
this.setState({[e.target.name]: [e.target.value]})
}
onSubmit(e){
e.preventDefault()
const user = {
first_name: this.state.first_name,
last_name: this.state.last_name,
email: this.state.email,
password: this.state.password
}
register(user).then(res=> {
this.props.history.push(`/login`)
})
}
render(){
return(
<div className="container">
<div className="row">
<div className="col-md-6 mt-5 mx-auto">
<form noValidate onSubmit={this.onSubmit}>
<h1 className="h3 mb-3 font-weight-normal">Please sign in</h1>
<div className="form-group">
<label htmlFor="first_name">First Name</label>
<input type="text"
className="form-control"
name="first_name"
placeholder="Enter First Name"
value={this.state.first_name}
onChange={this.onChange}/>
</div>
<div className="form-group">
<label htmlFor="last_name">Last Name</label>
<input type="text"
className="form-control"
name="last_name"
placeholder="Enter Last Name"
value={this.state.last_name}
onChange={this.onChange}/>
</div>
<div className="form-group">
<label htmlFor="email">Email Address</label>
<input type="email"
className="form-control"
name="email"
placeholder="Enter Email"
value={this.state.email}
onChange={this.onChange}/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input type="password"
className="form-control"
name="password"
placeholder="Enter Password"
value={this.state.password}
onChange={this.onChange}/>
</div>
<button type="submit"
className="btn btn-lg btn-primary btn-block">
Register
</button>
</form>
</div>
</div>
</div>
)
}
}
export default Register
../server.js
var cors = require ('cors')
var bodyParser = require("body-parser")
var app = express()
var port = process.env.PORT || 5000
app.use(bodyParser.json())
app.use(cors())
app.use(bodyParser.urlencoded({extended: false}))
var Users = require('./routes/users')
app.use('/users', Users)
app.listen(port, () => {
console.log("Server is running at port: " + port)
})
./client/src/UserFunctions.js
export const register = newUser => {
return axios
.post('users/register', {
first_name: newUser.firstname,
last_name: newUser.last_name,
email: newUser.email,
password: newUser.password
})
.then(res => {
console.log("Registered");
})
}
export const login = user => {
return axios
.post('users/login', {
email: user.email,
password: user.password
})
.then(res=>{
localStorage.setItem('usertoken', res.data)
return res.data
})
.catch(err => {
console.log(err)
})
}
Looking at this, it seems the problem may be with your client code.
You're trying to access http://localhost:3000/users/register, which is an inexistent route on your client but it exists on the server as http://localhost:5000/users/register. (that's assuming that your server is running on port 5000).
If your server is running on port 5000, you can try this in your register function...
return axios.post('http://localhost:5000/users/register') // add the rest of your code
Unless you have a proxy for your server set up in the client, you'll keep getting that error.