how to get cookie in react passed from express js api (MERN stack) - javascript

I have an api in express js that stores token in cookie on the client-side (react). The cookie is generated only when the user logins into the site. For example, when I test the login api with the postman, the cookie is generated as expected like this:
But when I log in with react.js then no cookie is found in the browser. Looks like the cookie was not passed to the front end as the screenshot demonstrates below:
As we got an alert message this means express api is working perfectly without any error!!
Here is my index.js file on express js that includes cookie-parser middleware as well
require("dotenv").config();
const port = process.env.PORT || 5050;
const express = require("express");
const app = express();
const cors = require("cors");
const authRouter = require("./routes/auth");
var cookieParser = require('cookie-parser')
connect_db();
app.use(express.json());
app.use(cookieParser())
app.use(cors());
app.use("/" , authRouter);
app.listen(port , () => {
console.log("Server is running!!");
})
Code for setting up the cookie from express api only controller
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const bcrypt = require('bcrypt')
const login = async (req, res) => {
const { email, password } = req.body;
try {
const checkDetails = await User.findOne({ email });
if (checkDetails) {
const { password: hashedPassword, token, username } = checkDetails;
bcrypt.compare(password, hashedPassword, function (err, matched) {
if (matched) {
res.cookie("token", token, { expires: new Date(Date.now() + (5 * 60000)) , httpOnly: true }).json({ "message": "You logged in sucessfully!" });
} else {
res.status(500).json({ "message": "Wrong password" });
}
});
} else {
res.status(500).json({ "message": "Wrong email" });
}
} catch (error) {
console.log(error.message);
}
}
Here is the react.js code that I am using to fetch data from api without using a proxy in package.json file
if (errors.length === 0) {
const isLogin = await fetch("http://localhost:5000/api/login", {
method: "POST",
body: JSON.stringify({ email, password }),
headers: {
"Content-Type": "application/json"
}
});
const res = await isLogin.json();
if(res) alert(res.message);
}
I want to get to know what is the reason behind this "getting cookie in postman but not in the browser". Do I need to use any react package?
The network tab screenshot might help you.
If I see in the network tab I get the same cookie, set among the other headers

To my understanding, fetch doesn't send requests with the cookies your browser has stored for that domain, and similarly, it doesn't store any cookies it receives in the response. This seems to be the expected behaviour of fetch.
To override this, try setting the credentials option when making the request, like so:
fetch(url, {
// ...
credentials: 'include'
})
or, alternatively:
fetch(url, {
// ...
credentials: 'same-origin'
})
You can read more about the differences between the two here.

I got my error resolved with two changings in my code
In front end just added credentials: 'include'
fetch(url, {
method : "POST"
body : body,
headers : headers,
credentials: 'include'
})
And in back end just replaced app.use(cors()); to
app.use(cors({ origin: 'http://localhost:3000', credentials: true, exposedHeaders: ['Set-Cookie', 'Date', 'ETag'] }))
That's it got resolved, Now I have cookies stored in my browser!!! Great. Thanks to this article:
https://www.anycodings.com/2022/01/react-app-express-server-set-cookie-not.html

during development i also faced same things, let me help you that how i solve it,
Firstly you use proxy in your react package.json, below private one:-
"private": true,
"proxy":"http://127.0.0.1:5000",
mention the same port on which your node server is running
Like:-
app.listen(5000,'127.0.0.1',()=>{
console.log('Server is Running');
});
above both must be on same , now react will run on port 3000 as usual but now we will create proxy to react So, react and node ports get connected on same with the help of proxy indirectly.
Now, when you will make GET or POST request from react then don't provide full URL, only provide the path on which you wants to get hit in backend and get response,
Example:-
React side on sending request, follow like this:-
const submitHandler=()=>{
axios.post('/api/loginuser',
{mobile:inputField.mobile,password:inputField.password})
.then((res)=>{
console.log(res);
})
.catch((err)=>{
console.log(err);
})
}
Node side where it will hit:-
app.post('/api/loginuser', async(req,res)=>{
//Your Code Stuff Here
res.send()
}
on both side same link should hit, it is very important
it will 100%.
don't forget to mention
on node main main where server is listening

Related

Is it possible to implement socket.io connection in express route?

I implement a payment service which depend on one of my express route as a callback route, so whenever a user want to make a payment, they will be redirected to this payment service link which entirely different my backend/frontend domain. After a successful payment, user will then be redirected to my express GET route (callback route), in this route is where I give users their asset and then redirect them to the frontend.
EXPECTATION
My expectation is, whenever a user make a purchase, I want a real time update on the frontend for others to see some details about the purchase without refreshing their browser.
WHAT I'VE TRIED
I had think socket.io would solve this, like adding a socket connection in the route to then push the data to the frontend. But after making lot of research, no solution seems to work for me.
HERE IS A SIMPLE CODE OF WHAT I'VE TRIED
=============================== server.js ========================
const express = require("express")
const app = express()
const http = require("http")
const cors = require("cors")
const session = require("express-session")
const runSocket = require("./runSocket")
const { Server } = require("socket.io")
app.use(cors())
app.use(express.json())
const server = http.createServer(app)
server.listen(3004, () => {
console.log("SERVER IS RUNNING")
})
const io = new Server(server, {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"],
},
})
const postRoute = require("./routes/postData")(io)
app.use("/post-data", postRoute)
==================================== postData Route ======================================
module.exports = function (io) {
router.post("/", async (req, res) => {
const data = req?.body?.data.message
const room = req?.body?.data?.room
io.on("connection", (socket) => {
console.log("Socket Running...")
socket.to(room).emit("the_message", data)
})
console.log("Under socket...")
return res.status(200).json({ data: req.body.data })
})
return router
}
This log: in postData route is not printing console.log("Socket Running...")
EXPECTATION
My expectation is, whenever a user make a purchase, I would like to make a real time update on the frontend for others to see some details about the purchase.
UPDATE: The Payment Gateway config looks somthing like this:
const { body } = await got.post("https://payment-provider-link", {
headers: { Authorization: "Bearer token for payment" },
json: {
email: "email#gmail.com",
amount: amount * 100,
initiate_type: "inline",
callback_url: `${BackendBaseUrl}/payment-callback`, // <<<============
},
})
Okay so you don't need the io.on("connection") in ur route. Remove that piece of code and simply change it to io.to(room).emit("the_message", data). Also make sure to have the other sockets joined the room ur trying to emit to otherwise they won't receive the data.

getting error 405 'Method not Allowed' When trying to send request to my node server

Its my first time using Express and MongoDB, i have created my Node server and connected it to my mongoDB database, but when i try to send an request from my html page to the server i get Error 405 method not allowed, following is my node.js server code
mongoose.connect('mongodb://localhost/userdatabase' ,{
useNewUrlParser: true,
useUnifiedTopology: true
})
const app = express()
app.use('/', express.static(path.join(__dirname, 'static')))
app.use(bodyParser.json())
const port = 5500
app.listen(port, () => {
console.log(`server is up at ${port}`)
})
app.post('/api/register', async(req, res) => {
const {username, password} = req.body
res.json({status: 'ok'})
try{
const response = await User.create({
username,
password
})
console.log('User created succesfully' , response)
}catch(error){
console.log(error)
}
})
and here is the function im trying to call to do the post request
const form = document.querySelector('#register')
form.addEventListener('submit', registerUser)
async function registerUser(event){
event.preventDefault()
const username = document.getElementById('username').value
const password = document.getElementById('password').value
const result = await fetch('/api/register', {
method: 'POST',
headers: {
'Content-Type' : 'application/json'
}, body: JSON.stringify({
username,
password
})
}).then(res => res.json())
}
basically i am creating an login system and try to register users, but for some reason i keep getting the error 405 when trying to call the Server, Note that for some reason it worked 3 times when i was trying earlier, I havent changed almost anything in the code but it just wont work, what it can be ? thanks in advance
You should tell in which port mongoDB would run.
const mongoose = require('mongoose');
main().catch(err => console.log(err));
async function main() {
await mongoose.connect('mongodb://localhost:27017/test');
}
I think you have to declare the server and port while calling the axios. The axios call should be - await fetch('localhost:5500/api/register'). It's searching for '/api/register' but didn't find anything. Hope this will solve your issue.
Issue solved : the html file wasn't in the folder 'static' 😅 probably i have moved it and didn't noticed, sorry for the question guys, if anyone have the same problem make sure to check it

Error: read ECONNRESET in request with Token in nodejs

I have a small API made in nodejs with express. A while ago I did not touch it and everything worked perfectly. Only now have I decided to implement JsonWebToken. In Postman, the login works fine, however, when trying to send the token as a header in a request I get an error. When i don't send the token in the request, response successfull (obviously since there is no token, the endpoint returns a 401 to me).
If I try to do it after authenticating (saving the token in an environment variable) and this time assigning it to the header, the following happens
If I send anything if it works, apparently it has to do with the length of the token.
I have tried it outside of postman, and the same thing happens, so the error does not seem to be from postman.
I don't know how to solve the problem, apparently nodejs does not handle the request by the length of the token.Is there a way to expand that?
The nodejs server entry point is:
// Enviroment process
require("dotenv").config();
// Body Parser
const bodyParser = require("body-parser");
const cors = require("cors");
// Express server
const app = require("express")();
app.use(cors());
// BodyParser middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Routes middleware
app.use(require("./routes/index"));
// Run server
app.listen(process.env.PORT, () => {
console.log(`Escuchando en el puerto ${process.env.PORT}`);
});
Routes:
const express = require("express");
const { checkToken } = require("../middlewares/authentication");
const app = express();
/// Base Routes
app.get(
"/equipments",
[checkToken],
require("../controllers/equipment/get_all.controller")
);
module.exports = app;
The checkToken middleware:
const jwt = require("jsonwebtoken");
const checkToken = (req, res, next) => {
const token = req.get("token") || req.query.token;
jwt.verify(token, process.env.SEED, (err, decoded) => {
if (err) {
return res.status(401).json({
ok: false,
error: {
message: "Invalid Token",
},
});
}
req.user = decoded.user;
next();
});
};
module.exports = {
checkToken,
};
The .env variables:
// Node env (development | production)
NODE_ENV=development
// Server Port
PORT=3000
// Token Time Expiration
TOKEN_EXPIRES=48h
// Token Seed
SEED=exampleseed
UPDATE
When I send the token through the body of the request, the error does not occur, and everything works correctly (obviously changing the middleware so that it receives it by the body). The problem is when I send it by headers or a query parameter.
const checkToken = (req, res, next) => {
// const token = req.get("token") || req.query.token;
const token = req.body.token;
jwt.verify(token, process.env.SEED, (err, decoded) => {
if (err) {
return res.status(401).json({
ok: false,
error: {
message: "Invalid Token",
},
});
}
req.user = decoded.user;
next();
});
};
UPDATE AND SOLUTION:
After trying only those files, I realized that the error did not come from these. The problem was in the authentication. When creating the token I used the information of the logged in user, however, I had not realized that it had a base64 image field.
// ... after login, user object contains object information
let token = jwt.sign(
{
user: {
id: user.id,
name: user.name,
image: user.image.base64Url
},
},
process.env.SEED,
{ expiresIn: process.env.TOKEN_EXPIRES }
);
The length of the base64 image made the token extremely long. Then when making the request and sending a string token with many characters, the reading error occurrs (Error: read ECONNRESET).
The solution was to ignore the image field when creating the token.
Finally, before an error of the same type, check that a field that contains too much information is not being sent.

I encountered a problem while working on my project on MERN Stack

I encountered a problem while working on my project on MERN Stack.
My React app is running on port 3000 and express api on 5000. What I encountered is, while adding 0auth functionality using redux, I am getting error like "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource here. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)."
Now the structure of my logic is like :
I have defined google strategy for passport. Defined routes in express route (http://localhost:5000/api/user/auth/google) and callback url (http://localhost:5000/api/user/auth/google/callback). Now when I am directly accessing "http://localhost:5000/api/user/auth/google", I am able to complete process, but when I am calling it through reducers from react app, I am getting above mentioned error.
My code is the following:
// Routes
router.get(
"/auth/google",
passport.authenticate("google", {
scope: ["profile", "email"]
})
);
router.get(
"/auth/google/callback",
passport.authenticate("google", {
failureRedirect: "/",
session: false
}),
function(req, res) {
var token = req.user.token;
console.log(res);
res.json({
success: true,
token: 'Bearer ' + token,
});
}
);
//Reducers Action
export const googleLoginUser = () => dispatch => {
axios
.get('api/users/auth/google')
.then((res) => {
//save to local Storage
const {
token
} = res.data;
// Set token to local storage
localStorage.setItem('jwtToken', token);
//set token to auth header
setAuthToken(token);
// Decode token to get user data
const decoded = jwt_decode(token);
console.log(decoded);
// set current user
dispatch(setCurrentUser(decoded));
})
.catch(err => {
console.log(err);
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
}
)
}
Allow CORS by using middleware for Express. Install CORS with npm install cors. Import CORS import cors from 'cors'. Use middleware with app.use(cors()) if your Express-instance is called app.
Example:
import express from 'express';
import cors from 'cors';
const app = express();
app.use(cors());
Let me know if it solves the problem

Post request in VueJs with undefined response

I am a beginner in VueJs and Expressjs. I am trying to make frontend side by Vuejs and backend by ExpressJs. I send a post request to the backend (expressJs) and :
1- Response is undefined
2- At the same time I can see 2 requests in chrome development tools. One is Option and another one is Post.
3- With postman there is no problem at all.
Here is the code of app.js in express
console.log('Server is running')
const express = require('express'),
bodyParser = require('body-parser'),
cors = require('cors'),
morgan = require('morgan');
app = new express();
//Setup middleware
app.use(cors());
app.use(morgan('combined'))
app.use(bodyParser.json())
app.post('/register', (req, res, next) => {
res.send({
message: `Hello ${req.body.email}! your user was registered!`
})
});
app.listen(8081);
And here is the code in VueJs :
// Api Setting
import axios from 'axios'
export const HTTP = axios.create({
baseURL: `http://localhost:8081`
});
// AuthenticationService
import { HTTP } from '../services/Api'
export default {
register(credentials) {
HTTP.post('register', credentials);
}
}
// Register Component
export default {
data() {
return {
email: '',
password: ''
};
},
methods: {
async register() {
const response = await AuthenticationService.register({
email: this.email,
password: this.password
});
console.log(response); // the value is undefined
}
}
};
I really don't know what I missed here that I get an undefined response and 2 requests at the same time. I appreciate any hint.
Whole code on github repo : here
Maybe. Authentication.register is not returning anything or more specifically a Promise which should be used to populate const response in the await call.
Try returning something like so: return HTTP.post('register', credentials); inside register.
For this to work though, HTTP.post('register', credentials) should also return something.
I use JSON.stringify to send the data, you are sending the objects directly, so
register(credentials) {
HTTP.post('register', credentials);
}
becomes
register(credentials) {
HTTP.post('register', JSON.stringify(credentials));
}

Categories