When I sign up a user, the header gets set in the /signup route.
Header token set successfully
But when I try to access the header on / route. The authorization fails because in auth.js, getting the header with const token = req.header('curToken') returns undefined. In the network log I can see that the header that has been set (curToken) is empty or non-existent, but is allowed. Can not get Header token
// index.js
const express = require('express')
require('./db/mongoose')
const userRouter = require('./routers/user')
const app = express()
const port = process.env.PORT || 3000
const cors = require('cors')
app.options('*', cors())
app.use(cors())
app.use(express.json())
app.use(userRouter)
app.listen(port, () => {
console.log(`Server is running on port ${port}`)
})
// user.js (express route)
const express = require('express')
const User = require('../models/user')
const auth = require('../middleware/auth')
const router = new express.Router()
// signup
router.post('/signup', async (req, res) => {
const user = new User(req.body)
try {
await user.save()
const token = await user.generateAuthToken()
res.set('curToken', token) // set header
console.log('registered')
res.send({ user, token })
} catch(err) {
res.status(400).send(err)
}
})
// test if token header is accesible
router.get('', auth, async (req, res) => {
try {
// const users = await User.find({})
res.send("logged in.")
} catch(err) {
res.send(err)
}
})
module.exports = router
// auth.js middleware
const jwt = require('jsonwebtoken')
const User = require('../models/user')
const auth = async (req, res, next) => {
res.header('Access-Control-Expose-Headers', 'curToken')
try {
const token = req.header('curToken') // get header
console.log('auth token:', token) // header returns undefined
const decoded = jwt.verify(token, 'thisismysecretcode')
const user = await User.findOne({ _id: decoded._id, 'tokens.token': token })
if (!user) {
throw new Error()
}
req.token = token
req.user = user
next()
} catch(err) {
res.status(401).send({error: 'Please authenticate.'})
}
}
module.exports = auth
// Sign Up
<template>
<div>
SignUp
<form #submit="sendRegData" #submit.prevent>
<input type="text" v-model="firstName" name="firstName" placeholder="First name"><br>
<input type="text" v-model="lastName" name="lastName" placeholder="Last name"><br>
<input type="text" v-model="email" name="email" placeholder="Email"><br>
<input type="text" v-model="password" name="password" placeholder="Password"><br>
<input type="submit" value="Send">
</form>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: "SignUp",
data() {
return {
firstName: null,
lastName: null,
email: null,
password: null
}
},
methods: {
async sendRegData() {
try {
await axios.post('http://localhost:3000/signup', {
firstName: this.firstName,
lastName: this.lastName,
email: this.email,
password: this.password
}).then((res) => {
let token = res.data.token
// console.log('token res received in front:', token)
// localStorage.setItem("currentToken", token)
// console.log('curToken:', localStorage.getItem("currentToken"))
})
} catch(err) {
console.log(err)
}
}
}
};
</script>
// login
<template>
<div class="home">
<!-- <h1>{{ User.firstName }}</h1> -->
</div>
</template>
<script>
import axios from 'axios';
export default {
name: "Page",
data() {
return {
Users: {},
dataFetched: false
}
},
async mounted() {
try {
this.Users = await axios.get('http://localhost:3000/')
console.log(this.Users)
// this.User = this.User.data[0] // transform first object from array
// this.dataFetched = true
} catch(err) {
console.error(err)
}
}
};
</script>
Related
I am trying to connect my vue js application to a msal b2c backend the login is done but now i need to make a button for password reset and sign up i cant find a sign up popup anywhere and i dont know how to set up a password reset popup.
When i click the password reset link in the login popup the popup closes and nothing happens after that
The way i currently have it set up is:
LoginView.vue
<template>
<div class="grid grid-cols-12">
<div class="default-container">
<p>u bent nog niet ingelogd log nu in</p>
<button type="button" #click="login">Login</button>
</div>
</div>
</template>
<script setup>
import useAuthStore from '../stores/AuthStore';
function login() {
useAuthStore().login();
}
</script>
Authstore.js
import { defineStore } from 'pinia';
import AuthService from '../services/AuthService';
const clientId = import.meta.env.VITE_APP_CLIENT_ID;
const authority = import.meta.env.VITE_APP_AUTHORITY;
const scopes = [import.meta.env.VITE_APP_SCOPE_READ];
const authService = new AuthService(clientId, authority, scopes);
const useAuthStore = defineStore('AuthStore', {
state: () => ({
isAuthenticated: !!localStorage.getItem('apiToken'),
apiToken: localStorage.getItem('apiToken'),
user: JSON.parse(localStorage.getItem('userDetails')),
error: null,
}),
getters: {
isLoggedIn: (state) => state.isAuthenticated,
currentApiToken: (state) => state.apiToken,
currentUser: (state) => state.user,
currentError: (state) => state.error,
},
actions: {
async login() {
try {
const token = await authService.login();
this.apiToken = token.apiToken;
localStorage.setItem('apiToken', token.apiToken);
this.isAuthenticated = true;
fetch(`${import.meta.env.VITE_APP_API_URL}/account/current`, {
headers: {
Authorization: `Bearer ${token.apiToken}`,
},
})
.then((response) => response.json())
.then((data) => {
localStorage.setItem('userDetails', JSON.stringify(data));
this.user = data;
});
} catch (error) {
this.error = error;
}
},
async logout() {
try {
await authService.logout();
this.user = null;
this.apiToken = null;
this.isAuthenticated = false;
localStorage.removeItem('apiToken');
localStorage.removeItem('userDetails');
} catch (error) {
this.error = error;
}
},
},
});
export default useAuthStore;
AuthService.js
import * as Msal from 'msal';
export default class AuthService {
constructor(clientId, authority, scopes) {
this.app = new Msal.UserAgentApplication({
auth: {
clientId,
authority,
postLogoutRedirectUri: window.location.origin,
redirectUri: window.location.origin,
validateAuthority: false,
},
cache: {
cacheLocation: 'localStorage',
},
});
this.scopes = scopes;
}
async login() {
const loginRequest = {
scopes: this.scopes,
prompt: 'select_account',
};
const accessTokenRequest = {
scopes: this.scopes,
};
let token = {};
try {
await this.app.loginPopup(loginRequest);
} catch (error) {
return undefined;
}
try {
const acquireTokenSilent = await this.app.acquireTokenSilent(accessTokenRequest);
token = {
apiToken: acquireTokenSilent.accessToken,
expiresOn: acquireTokenSilent.expiresOn,
};
} catch (error) {
try {
const acquireTokenPopup = await this.app.acquireTokenPopup(accessTokenRequest);
token = {
apiToken: acquireTokenPopup.accessToken,
expiresOn: acquireTokenPopup.expiresOn,
};
} catch (errorPopup) {
return undefined;
}
}
return token;
}
logout() {
this.app.logout();
}
}
I'm following a Udemy MERN stack course and I am quite a beginner ,I've got stuck in middle of a problem. There is no point in completing it before solving this problem. The problem is with the concept of authorization and concept of protected roles, so when the user is logged in to the interface we have to check whether is user is authorized or not. I followed the instructer end to end exactly according to the instruction and his code.
Using jsonwebtoken, verifiationn is conducted on the basis of encrypted token. whos key is stored in .env file
The output of the network dev tool in the browser :
enter image description here
I have no idea what causes this.
server.js
const express = require("express");
const app = express();
require("dotenv").config();
const dbConfig = require("./config/dbConfig.js");
app.use(express.json());
const userRoute = require("./routes/userRoute");
app.use("/api/user", userRoute);
const port = process.env.PORT || 5000;
console.log(process.env.MONGO_URL);
app.listen(port, () => console.log(`Node server started at port ${port}`));
.env
MONGO_URL = 'mongodb+srv://users:root#cluster0.vnoq4f8.mongodb.net/ngodatabase';
JWT_SECRET = 'ngo_project';
Home.js
import React, { useEffect } from "react";
import axios from "axios";
function Home() {
const getData = async () => {
try {
const response = await axios.post(
"/api/user/get-user-info-by-id",
{},
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
}, // headers
}
);
console.log(response.data);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getData();
}, []);
return <div>Home</div>;
}
export default Home;
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,
});
}
};
userRoute.js
const express = require("express");
const router = express.Router();
const User = require("../models/userModel");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const authmiddleware = require("../middlewares/authmiddleware");
router.post("/register", async (req, res) => {
try {
const userExist = await User.findOne({ email: req.body.email });
if (userExist) {
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);
await newuser.save();
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 user = await User.findOne({ email: req.body.email });
if (!user) {
return res
.status(200)
.send({ message: "User does not exist", 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 token = jwt.sign({ id: user._id }, 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 });
if (!user) {
return res
.status(200)
.send({ message: "User does not exist", success: false });
} else {
res.status(200).send({
success: true,
data: {
name: user.name,
email: user.email,
},
});
}
} catch (error) {
res.status(500).send({
message: "Error getting user information",
success: false,
error,
});
}
});
module.exports = router;
package.json
jsonwebtoken in package
Login.js
import { Button, Form, Input } from "antd";
import React from "react";
import toast from "react-hot-toast";
import { Link, useNavigate } from "react-router-dom";
import axios from "axios";
function Login() {
const navigate = useNavigate();
const onFinish = async (values) => {
try {
const response = await axios.post("/api/user/login", values);
if (response.data.success) {
toast.success(response.data.message);
toast("Redirecting to home page");
localStorage.setItem("token", response.data.data);
navigate("/");
} else {
toast.error(response.data.message);
}
} catch (error) {
toast.error("Something went wrong");
}
};
return (
<div className="authentication">
<div className="authentication-form card p-4">
<h1 className="card-title">Welcome Back</h1>
<Form layout="vertical" onFinish={onFinish}>
<Form.Item label="Email" name="email">
<Input placeholder="Email"></Input>
</Form.Item>
<Form.Item label="Password" name="password">
<Input placeholder="Password" type="password"></Input>
</Form.Item>
<Button className="primary-button my-2" htmlType="submit">
LOGIN
</Button>
<Link to="/register" className="anchor mt-2">
CLICK HERE TO REGISTER
</Link>
</Form>
</div>
</div>
);
}
export default Login;
Register.js
import { Button, Form, Input } from "antd";
import React from "react";
import { Link, useNavigate } from "react-router-dom";
import axios from "axios";
import toast from "react-hot-toast";
function Register() {
const navigate = useNavigate();
const onFinish = async (values) => {
try {
const response = await axios.post("/api/user/register", values);
if (response.data.success) {
toast.success(response.data.message);
toast("Redirecting to login page");
navigate("/login");
} else {
toast.error(response.data.message);
}
} catch (error) {
toast.error("Something went wrong");
}
};
return (
<div className="authentication">
<div className="authentication-form card p-4">
<h1 className="card-title">Nice to meet you</h1>
<Form layout="vertical" onFinish={onFinish}>
<Form.Item label="Name" name="name">
<Input type="text" placeholder="Name" name="name"></Input>
</Form.Item>
<Form.Item label="Email" name="email">
<Input type="email" placeholder="Email" name="email"></Input>
</Form.Item>
<Form.Item label="Password" name="password">
<Input
placeholder="Password"
name="password"
type="password"
></Input>
</Form.Item>
<Button
className="primary-button my-2"
htmlType="submit"
name="submit"
>
REGISTER
</Button>
<Link to="/Login" className="anchor mt-2">
CLICK HERE TO LOGIN
</Link>
</Form>
</div>
</div>
);
}
export default Register;
did you check if you already have the token in your storage ?
check using inspectElement, or try to print the token in authmiddleware.js
like:
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) {
console.log(token); //this line will print the token that given in your request
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,
});
}
};
I'm having a hard time trying to fix my login page
I've provided a very short youtube video on what is the problem that I encountered.
Youtube Link: https://youtu.be/lpyJo6tmiRs
It works properly on localhost but breaks when I deploy to herkou & netlify.
Register function also works properly
I provided everything here and also hidden some important info like mongodb user and passwords.
Website Link
https://incomparable-speculoos-abdd5f.netlify.app/
Login Page
import React, { useState, useEffect } from 'react'
import { useNavigate } from "react-router-dom"
import Axios from 'axios'
import './login.css'
import Register from '../register/register'
const Login = () => {
const navigate = useNavigate();
const [style, setStyle] = useState('hidden')
const [border, setBorder] = useState(false)
const [email, setEmail] = useState('')
const [password, setPass] = useState('')
const [errMsg, setErr] = useState('')
Axios.defaults.withCredentials = true;
const handleEmail = (e) => {
setEmail(e.target.value)
}
const handlePassword = (e) => {
setPass(e.target.value)
}
const show = () => [
setStyle('registerParent')
]
const hide = () => {
setStyle('hidden')
}
const reloadA = () => {
window.location.reload(false);
}
// FUNCTION WHEN LOGIN IS CLICKED
const login = () => {
Axios.post('https://votereact-app.herokuapp.com/login',
{email: email,
password: password,
}).then((response) => {
// CHECKS IF THERE IS A MESSAGE FROM THE BACKEND (MEANS THERE IS A PROBLEM IN THE LOGIN)
if (response.data.message) {
setErr(response.data.message)
setBorder(true)
} else {
// NAVIGATES TO /home ROUTE OF THERE IS NO MESSAGE (/route redirects to privateRoute)
setErr("Logged in")
setBorder(false)
navigate('/home', {replace: true})
}
})
}
return (
<>
<div className="loginParent">
<div className="loginContainer">
<h1 className="vote-login">VoteReact</h1>
<div className="loginBox">
<div className="inputs-parent">
<input type="text" style={{border: border ? '1px solid #e2252b' : '1px solid #1B74E4'}} placeholder="Email" className="email-input" onChange={handleEmail}></input>
<input type="password" style={{border: border ? '1px solid #e2252b' : '1px solid #1B74E4'}}placeholder="Password" className="password-input" onChange={handlePassword}></input>
<p className="errMsg">{errMsg}</p>
</div>
<button className="loginButton" onClick={login}>Log in</button> {/* LOGIN BUTTON */}
<p className="forgot">Forgot Password?</p>
<button className="signup" onClick={show}>Sign up</button>
</div>
</div>
</div>
<Register styleName={style.toString()} close={() => hide()} load={() =>reloadA()}/>
</>
)
}
export default Login
BACK END CODE
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose")
const app = express();
const bcrypt = require("bcryptjs")
const saltRounds = 10;
const bodyParser = require("body-parser")
const cookieParser = require("cookie-parser")
const session = require("express-session")
const voterModel = require('./modules/voters.js')
const presidentModel = require('./modules/president.js')
const viceModel = require('./modules/vice.js')
const treasurerModel = require('./modules/treasurer.js')
app.use(express.json());
require('dotenv').config();
app.use(cors({credentials: true, origin: 'https://incomparable-speculoos-abdd5f.netlify.app'}));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }))
app.use(session({
key: "userId",
secret: "hidden",
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 60000
}
}))
mongoose.connect("hidden",
{
useNewUrlParser: true,
useUnifiedTopology: true
}
)
// GET THE SESSION AND CHECK IF IT DOES EXIST OR NO
//IF YES THEN LOGGEDIN: TRUE ELSE, FALSE
// --- HERE IS WHERE I ENCOUNTER PROBLEM, IT SHOULD RETURN TRUE AFTER I LOG IN BUT STILL RETURNS FALSE ---
app.get('/login', async (req, res) => {
if (req.session.voter) {
res.send({loggedIn: true})
} else {
res.send({loggedIn: false})
}
})
app.post('/login', async (req, res) => {
const email = req.body.email;
const password = req.body.password;
// CHECKS IF USER EMAIL EXISTS
voterModel.find({email: email}, {"email":1}, async (err, result) => {
if (err) {
console.log(err)
} else {
if(result.length > 0) {
// COMPARES PASSWORD IF IT IS CORRECT
const user = await voterModel.findOne({email: email})
const pass = await user.comparePassword(password)
if (pass) {
// SAVE THE SESSION IF PASS IS CORRECT
req.session.voter = result
var oneWeek = 60 * 60 * 24; //1 week
req.session.voter.expires = new Date(Date.now() + oneWeek);
req.session.voter.maxAge = oneWeek;
console.log(req.session.voter)
res.send(result)
} else {
console.log("NOT LOGGED IN")
res.send({ message: 'Invalid email or password!'})
}
} else {
console.log("NOT LOGGED IN")
res.send({ message: 'Invalid email or password!'})
}
}
})
})
app.post('/register', async (req, res) => {
const username = req.body.username;
const email = req.body.email;
const password = req.body.password;
// HASING PASSWORD
bcrypt.hash(password, saltRounds, async (err, hash) => {
if (err) {
console.log(err)
}
// INSERTING VALUES
const voters = await voterModel({email: email, username: username, password: hash, status: false})
// CHECKS IF EMAIL IS IN USE
const isNewEmail = await voterModel.isThisEmailInUse(email)
if (!isNewEmail) return res.send({ message: 'This email is already taken!'})
// SAVES THE INSERT DATA FOR VOTERS
await voters.save()
res.send({success: true})
})
})
app.post('/logout', (req, res) => {
if(req.session.voter) {
req.session.voter = null;
req.session.destroy();
}
})
const PORT = process.env.PORT || 3001
app.listen(PORT, () => {
console.log('Running on port successfuly')
})
Private Route to Home
import React, { useState, useEffect } from 'react'
import { useNavigate } from "react-router-dom"
import Axios from 'axios'
import Home from "./home/home.js"
const PrivateRoute = () => {
Axios.defaults.withCredentials = true;
const navigate = useNavigate();
const [loggedIn, setLoggedIn] = useState(false);
useEffect(()=> {
// GET DATA FROM axios.get(/login) on backend
Axios.get("https://votereact-app.herokuapp.com/login").then((response) => {
if (response.data.loggedIn === true) {
setLoggedIn(true);
console.log(response)
} else {
navigate("/" , {replace: true})
console.log(response)
}
})
},[])
// WHILE CHECKING IF Logged in or not
if (!loggedIn) {
return (
<>
Loading...
</>
)
}
// Redirects to real home page if user is logged in
return (
<>
<Home/>
</>
)
}
export default PrivateRoute
I'm following a tutorial to build a full stack app using VueJS and the MEVN stack. I have
a) built mongo db
b) build api back end with one mongoose model 'Student'
c) got the back end api running at localhost:4000/api
d) got the front end running with VueJS and Axios to read data from
the api
e) got READ, CREATE and DELETE working fine from my VueJS app
f) UPDATE is not working
g) Postman PUT is working fine though, so I know the back end is
fine.
Back end routes are
const express = require('express');
const studentRoute = express.Router();
// model
let StudentModel = require('../models/Student');
studentRoute.route('/create-student').post((req, res, next) => {
console.log('creating one student at /create-student')
StudentModel.create(req.body, (error, data) => {
if (error) {
return next(error)
} else {
console.log(`student created ${JSON.stringify(data)}`)
res.json(data)
}
})
});
studentRoute.route('/').get((req, res, next) => {
console.log('GET all students')
StudentModel.find((error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
studentRoute.route('/edit-student/:id').get((req, res, next) => {
console.log('get one student at /edit-student/:id')
StudentModel.findById(req.params.id, (error, data) => {
if (error) {
return next(error)
} else {
res.json(data)
}
})
})
// Update
studentRoute.route('/update-student/:id').post((req, res, next) => {
console.log(`attempting to update one student with id ${req.params.id}`)
console.log(`request body = `)
console.log(JSON.stringify(req.body))
console.log(req.body)
StudentModel.findByIdAndUpdate(req.params.id,
{ $set: req.body },
(error, data) => {
if (error) {
console.log(`an error has taken place`)
return next(error);
} else {
res.json(data)
console.log('Student successfully updated!')
}
})
})
// Delete
studentRoute.route('/delete-student/:id').delete((req, res, next) => {
console.log('delete one student at /delete-student/:id')
StudentModel.findByIdAndRemove(req.params.id, (error, data) => {
if (error) {
return next(error);
} else {
res.status(200).json({
msg: data
})
}
})
})
module.exports = studentRoute;
front end update code is
<template>
<div class="row justify-content-center">
<div class="col-md-6">
<h3 class="text-center">Update Student</h3>
<form #submit.prevent="handleUpdateForm">
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" v-model="student.name" required>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" v-model="student.email" required>
</div>
<div class="form-group">
<label>Phone</label>
<input type="text" class="form-control" v-model="student.phone" required>
</div>
<div class="form-group">
<button class="btn btn-danger btn-block">Update</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts">
import { Vue } from 'vue-class-component';
import axios from "axios";
export default class EditComponent extends Vue {
student!: {
name: '',
email: '',
phone: ''
}
data() {
return {
student: { }
}
}
created() {
let apiURL = `http://localhost:4000/api/edit-student/${this.$route.params.id}`;
axios.get(apiURL).then((res) => {
this.student = res.data;
})
}
handleUpdateForm() {
let id = this.$route.params.id
let apiURL = `http://localhost:4000/api/update-student/${this.$route.params.id}`;
console.log(`attempt to update student at url`)
console.log(apiURL)
console.log(`with id`)
console.log(id)
console.log(`attempt to update student ${JSON.stringify(this.student)}`)
axios.put(apiURL, this.student)
.then(res => {
console.log(`response is ${res}`)
this.$router.push('/view')
})
.catch(error => {
console.log('error when updating student')
console.log(error)
});
}
}
</script>
when I use Postman I get this response from the api
attempting to update one student with id 6119d671cc9ce131207bd37c
request body =
{"_id":"6119d671cc9ce131207bd37c","name":"PHIL","email":"philanderson888#hotmail.com","phone":7888849991,"__v":0}{ _id: '6119d671cc9ce131207bd37c',
name: 'PHIL',
email: 'philanderson888#hotmail.com',
phone: 7888849991,
__v: 0 }
Student successfully updated!
when I use VueJS to update my Student I get the following error from this code
// Update
studentRoute.route('/update-student/:id').post((req, res, next) => {
console.log(`attempting to update one student with id ${req.params.id}`)
console.log(`request body = `)
console.log(JSON.stringify(req.body))
console.log(req.body)
StudentModel.findByIdAndUpdate(req.params.id,
{ $set: req.body },
(error, data) => {
if (error) {
console.log(`an error has taken place`)
return next(error);
} else {
res.json(data)
console.log('Student successfully updated!')
}
})
})
attempt to update student at url
EditComponent.vue?720f:29 http://localhost:4000/api/update-student/6119d671cc9ce131207bd37c
EditComponent.vue?720f:30 with id
EditComponent.vue?720f:31 6119d671cc9ce131207bd37c
EditComponent.vue?720f:32 attempt to update student {"_id":"6119d671cc9ce131207bd37c","name":"PHIL","email":"phil#phil.com","phone":123,"__v":0}
xhr.js?b50d:177 PUT http://localhost:4000/api/update-student/6119d671cc9ce131207bd37c 404 (Not Found)
dispatchXhrRequest # xhr.js?b50d:177
xhrAdapter # xhr.js?b50d:13
dispatchRequest # dispatchRequest.js?5270:52
Promise.then (async)
request # Axios.js?0a06:61
Axios.<computed> # Axios.js?0a06:87
wrap # bind.js?1d2b:9
handleUpdateForm # EditComponent.vue?720f:33
eval # EditComponent.vue?2308:5
eval # runtime-dom.esm-bundler.js?830f:1400
callWithErrorHandling # runtime-core.esm-bundler.js?5c40:6988
callWithAsyncErrorHandling # runtime-core.esm-bundler.js?5c40:6997
invoker # runtime-dom.esm-bundler.js?830f:347
EditComponent.vue?720f:39 error when updating student
EditComponent.vue?720f:40 Error: Request failed with status code 404
at createError (createError.js?2d83:16)
at settle (settle.js?467f:17)
at XMLHttpRequest.handleLoad (xhr.js?b50d:62)
I'm aware mongo has updated their methods for handling updates and have tried the following
1)
StudentModel.findByIdAndUpdate(req.params.id,
{ $set: req.body },
(error, data) => {
StudentModel.findOneAndUpdate({_id:req.params.id},
{ $set: req.body },
(error, data) => {
StudentModel.updateOne({_id:req.params.id},
{ $set: req.body },
(error, data) => {
In each case I am getting the error above and in each case Postman works fine. So there's a problem with the URL being formed and I'm not sure what it is???
Your help would be appreciated!
Thank you
Philip
Also, just in case it is relevant, here is the back end app.js
let express = require('express'),
cors = require('cors'),
mongoose = require('mongoose'),
database = require('./database'),
bodyParser = require('body-parser');
// Connect mongoDB
mongoose.Promise = global.Promise;
//mongoose.set('useFindAndModify',false);
mongoose.connect(database.db, {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log("Database connected")
},
error => {
console.log("Database could't be connected to: " + error)
}
)
const studentAPI = require('../api/routes/student.route')
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cors());
// API
app.use('/api', studentAPI)
// Create port
const port = process.env.PORT || 4000;
const server = app.listen(port, () => {
console.log('Connected to port ' + port)
})
const logUsage = (logCode) => {
console.log(`http serving with code ${logCode}`)
}
app.use((req, res, next) => {
console.log(`logging data in 'next'`)
next(logUsage(200));
});
app.use(function (err, req, res, next) {
console.log('in app.use')
console.error(err.message);
if (!err.statusCode) err.statusCode = 500;
res.status(err.statusCode).send(err.message);
});
You can try to replace post in update route with put
I use VueJS (cli 3) & axios, and NodeJS - ExpressJS in the back-end. I am trying to secure my post user edit using CSRF token.
Vue View (edit user - focus to mySubmitEd):
<template>
<div class="one-user">
<h1>this user</h1>
<h2>{{name}} - {{surname}} - {{ perm }}</h2>
<h2>Edit</h2>
<input type="text" v-model="name">
<input type="text" v-model="surname">
<input type="text" v-model="perm">
<button #click="mySubmitEd">Edit</button>
<button #click="mySubmit">Delete</button>
</div>
</template>
<script>
import axios from 'axios'
import io from 'socket.io-client'
export default {
name: 'one-user',
data () {
return {
name: '',
surname: '',
perm: '',
csrf: '',
id: this.$route.params.id,
socket: io('localhost:7000')
}
},
mounted () {
axios.get('http://localhost:7000/api/get-user/' + this.id)
.then(res => {
const data = res.data.user
this.name = data.name
this.surname = data.last_name
this.perm = data.permalink
this.csrf = res.data.csrfToken
axios.defaults.headers.common['X-CSRF-TOKEN'] = this.csrf
})
.catch(error => console.log(error))
},
methods: {
mySubmit () {
const formData = {
_id: this.id
}
axios.post('http://localhost:7000/api/delete-user', formData)
.then(this.$router.push({ name: 'get-user' }))
.catch(error => console.log(error))
},
mySubmitEd () {
const formData = {
_id: this.id,
name: this.name,
last_name: this.surname,
permalink: this.perm,
_csrf: this.csrf
}
console.log(formData._csrf)
axios.post('http://localhost:7000/api/update-user', formData)
.catch(error => console.log(error))
}
}
}
</script>
server.js file:
...
const cookieParser = require('cookie-parser');
const csurf = require('csurf');
...
app.use(cookieParser());
const csrfProtection = csurf({ cookie: true });
app.use(csrfProtection);
...
back-end controller which get the user:
controller.getOneUser = function(req, res) {
User.findOne({ _id: req.params.userId }).exec(function(err, user) {
res.json({user, csrfToken: req.csrfToken()});
});
};
back-end update post:
controller.updateUser = function(req, res) {
User.findById(req.body._id, function(err, user) {
user.set({
name: req.body.name,
last_name: req.body.last_name,
permalink: req.body.permalink,
price: req.body.price
});
user.save();
res.send(user);
});
};
My errors in NodeJS-exress console:
ForbiddenError: invalid csrf token
My errors in browser:
POST http://localhost:7000/api/update-user 403 (Forbidden)
I don't know what is happened because I see in network tab(chrome) the csrf token is the same in the headers and what I send (ex.):
X-CSRF-TOKEN: PddyOZrf-AdHppP3lMuWA2n7AuD8QWFG3ta0
_csrf: "PddyOZrf-AdHppP3lMuWA2n7AuD8QWFG3ta0"
I don't know what I have miss here. I can't find where is the problem.
If you want more information please asked me to help you.
I had to pass in the headers the cookie correctly, so I did 2 corrections:
First in Vue view:
I passed credentials:
axios.create({withCredentials: true}).get(...)
and
axios.create({withCredentials: true}).post(...)
and secondly in server.js file before routes I put this:
...
const corsOptions = {
origin: 'http://localhost:8080',
credentials: true,
}
app.use(cors(corsOptions));
app.use(bodyParser.json());
app.use(cookieParser());
const csrfProtection = csurf({ cookie: true });
app.use(csrfProtection);
app.use(function (req, res, next) {
res.cookie('XSRF-TOKEN', req.csrfToken());
res.locals._csrf = req.csrfToken();
next();
});
...