I am using Express for my Back end of my React app when i set a session in a page and redirect to another page of my web app the session deleted
Here my express code :
async function createUser(req, res, next) {
try {
let parameters = req.body
let user = await models.User.create({
displayName: parameters.displayName,
phone: parameters.phone,
sex: parameters.sex,
password: parameters.password,
})
req.session.user = user.dataValues;
res.json({
status: 'success',
user,
})
}
and here is my react code :
onSubmit = (event) => {
event.preventDefault()
request.post('/newuser',{
displayName:this.state.name,
phone:this.state.phone,
password:this.state.password,
sex:this.state.sex
})
.then(function(response){
this.props.authenticate(true)
this.setState({
auth:true
})
}.bind(this))
}
and here is my react render method:
render(){
if(this.state.auth)
return <Redirect to='/profile' />;
}
with all this describes when i redirected to the profile page i dont have any session and all hope is gone :))
please help me solve this problem .
When you use axios for sending request you should do this :
In Front (React) :
You should set withCredentials: true in axios setting like this :
import axios from 'axios'
import config from '../../config'
const request = axios.create({
baseURL: config.url,
timeout: 20000,
withCredentials: true,
});
export default request
In Back (Node/Express) : you should add this code the the cors
const express = require('express')
const cors = require('cors')
app.use(cors({
origin:['http://localhost:9520']//your front url,
methods:['GET','POST'],
credentials: true
}))
I figured it out by searching, Thanks for not helping though :))
Related
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
I know there are a lot of other "works in postman and not in browser" posts, but I've read through them and cannot find anything to give direction on what I'm not catching here. Most of those had to do with proxy issues, but I dont have any proxy's set up.
I recently changed from using a pymongo backend to mongoose/express. My find() works for the get all clients just fine on the browser side, but the findOne() get comes back undefined (I was getting an unexpected token JSON error but that is resolved although I dont know what actually fixed it), yet in Postman it brings exactly what I'm looking for. I'm assuming its something simple, but I can't seem to spot it.
Backend-
index.js
const express = require("express")
const mongoose = require("mongoose")
const cors = require('cors')
const clientRoutes = require("./routes/clientRoutes")
const contractRoutes = require("./routes/contractRoutes")
const bodyParser = require('body-parser');
mongoose
.connect("MONGODB URL", { useNewUrlParser: true })
.then(() => {
const app = express()
app.use(express.json())
app.use(cors())
app.use(bodyParser.json());
app.use("/api", clientRoutes)
app.use("/api", contractRoutes)
app.listen(5000, () => {
console.log("Server has started")
})
})
Schema
const mongoose = require("mongoose")
const schema = mongoose.Schema({
clientId: Number,
firstName: String,
lastName: String,
phone: String,
contracts: [{
contractId: Number,
authNumber: String,
contType: String,
contHours: Number,
contStartDate: Date,
contEndDate: Date
}],
})
module.exports = mongoose.model("Client", schema)
routes-
const express = require("express")
const Client = require("../models/Client.js")
const router = express.Router()
//Client routes
router.get("/clients", async (req, res) => {
const clients = await Client.find()
res.send(clients)
})
router.get("/clients/:clientId", async (req, res) => {
try {
const client = await Client.findOne({ clientId: req.params.clientId })
res.send(client)
} catch {
res.status(404)
res.send({ error: "Client not found"})
}
})
React frontend component making the request-
import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import ChartNav from './ChartNav';
import ClientContext from './ClientContext';
class ClientChart extends React.Component {
static get propTypes() {
return {
match: PropTypes.any,
clientId: PropTypes.any
}
}
constructor (props){
super(props);
this.state = {
clientId: this.props.match.params.clientId,
client: {},
isLoading: true,
errors: null
};
console.log(this.state.clientId)
}
componentDidMount(){
fetch(`http://localhost:5000/api/clients/${this.state.clientId}`)
.then(res => res.json())
.then(
result => {
let client = JSON.parse(result.data);
this.setState({
isLoading: false,
client: client,
});
}, [])
.catch(error => this.setState({
error: error.message,
isLoading: false,
}));
}
console and response
404
XHR GET http://localhost:5000/api/clients/undefined
error "Client not found"
So in trying to track it down, I switched clientId back to id (which I had been using previously, and changed the prop in the DB for 1 client back to id to test), and calling console.log after the initial response from the fetch showed the data coming through. When I setState from that initial response, all props populated where they should. In reverting the id back to clientId and changing the routes, and using a client with the clientId field, etc., nothing works again. So if anyone knows why React is happy with id but not clientId as an identifier, please let me know. Even weirder is that its able to call all the other clients who I still have listed with clientId, and the routes are calling by clientId, not id... so Im at a total loss as to whats happening under the hood.
Below is the working get call (I also threw in axios at one point in trying to track it down and left it there, but initially it did not make any difference).
axios.get(`http://localhost:5000/api/clients/${this.state.id}`)
.then((response) => {
const data = response.data;
console.log(response.data);
this.setState({
client: data,
isLoading: false,
});
}, [])
I am trying to do Spotify Authentication using Client(React) and Server, the logging in works for a second then the page refreshes immediately after logging in and logs the user out. Anyone knows where might be the problem?
Here is my code:
server.js:
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const SpotifyWebApi = require('spotify-web-api-node');
const app = express();
app.use(cors()) // to handle the cross-origin requests
app.use(express.json()); // to parse JSON bodies
const port = process.env.PORT || 8000;
const credentials = {
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
redirectUri: process.env.REDIRECT_URI || "http://localhost:3000"
};
app.post('/refresh', (req, res) => {
const refreshToken = req.body.refreshToken;
// console.log("Hii");
let spotifyApi = new spotifyWebApi({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
redirectUri: process.env.REDIRECT_URI,
refreshToken,
});
spotifyApi
.refreshAccessToken()
.then((data) => {
// console.log(data.body);
res.json({
accessToken: data.body.access_token,
expiresIn: data.body.expires_in,
})
})
.catch((err) => {
console.log(err);
res.sendStatus(400);
});
});
app.post('/login', (req,res) => {
// Get the "code" value posted from the client-side and get the user data from the spotify api
let spotifyApi = new spotifyWebApi(credentials)
const code = req.body.code
spotifyApi.authorizationCodeGrant(code).then((data) => {
// Returning the User's Data in the json formate
res.json({
accessToken : data.body.access_token,
refreshToken : data.body.refresh_token,
expiresIn : data.body.expires_in
})
})
.catch((err) => {
console.log(err);
res.sendStatus(400)
})
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
Client side:
useAuth.js:
import React from 'react';
import { useEffect, useState } from 'react';
import axios from "axios"
export default function useAuth(code) {
const [accessToken, setAccessToken] = useState();
const [refreshToken, setRefreshToken] = useState();
const [expiresIn, setExpiresIn] = useState();
useEffect(() => {
axios
.post("/login", {code})
.then((res) => {
window.history.pushState({}, null, "/");
console.log(res.data);
setAccessToken(res.data.accessToken);
setRefreshToken(res.data.refreshToken);
setExpiresIn(res.data.expiresIn);
})
.catch(() => {
window.location = "/";
});
}, [code]);
useEffect(() => {
if (!refreshToken || !expiresIn) {
return;
}
let interval = setInterval(() => {
axios
.post("/refresh", {refreshToken})
.then((res) => {
setAccessToken(res.data.accessToken);
setExpiresIn(res.data.expiresIn);
})
.catch(() => {
window.location = "/";
});
}, (expiresIn - 60) * 1000);
return () => clearInterval(interval)
}, [refreshToken, expiresIn]);
return accessToken;
}
spotifyConfig.js:
const authEndpoint = "https://accounts.spotify.com/authorize";
const redirectUri = "http://localhost:3000";
const clientId = "ea28d4ba34f34b44b59c640052c6e098";
const scopes = [
"streaming",
"playlist-modify-public",
"ugc-image-upload",
"user-read-email",
"user-read-private",
"user-read-currently-playing",
"user-read-recently-played",
"user-read-playback-state",
"user-modify-playback-state"
];
export const loginUrl = `${authEndpoint}?client_id=${clientId}&response_type=code&redirect_uri=${redirectUri}&scope=${scopes.join(
"%20"
)}&show_dialog=true`;
App.js:
import './App.css';
import Dashboard from './pages/Dashboard';
import Login from './components/Login';
const code = new URLSearchParams(window.location.search).get('code')
function App() {
return (
<div>
{code ? <Dashboard code={code}/> : <Login/>}
</div>
);
}
export default App;
👉🏽 this page appears a second then logs out Dashboard.js:
import React, {useEffect} from 'react';
import useAuth from '../useAuth';
import SpotifyWebApi from "spotify-web-api-node";
const spotifyApi = new SpotifyWebApi({
clientId: "ea28d4ba34f34b44b59c640052c6e098",
});
export default function Dashboard({code}) {
const accessToken = useAuth(code);
useEffect(() => {
if (!accessToken) return;
spotifyApi.setAccessToken(accessToken);
spotifyApi.getMe().then(data => {
console.log(data);
})
}, []);
return (
<div>
This is the home page 🏠
</div>
)
}
Login.js:
import React from 'react';
import { loginUrl } from '../spotifyConfig';
export default function Login() {
return (
<div>
<a href={loginUrl}>
<button>LOGIN WITH SPOTIFY</button>
</a>
<div className="links">
<p>
⚠ When joining or creating a Queue, open Spotify to be able to queue up tracks
</p>
</div>
</div>
)
}
I experienced a similar issue. Here are a few steps that helped me to resolve it and many of the subsequent issues I encountered.
Run your IDE's debugger and set break points for your /login request. Also, check whether your environment variables are getting set as you intend (if running VSCode you can learn how to set this up here). In particular, make sure your credentials
clientId: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, redirectUri: process.env.REDIRECT_URI
are correct. If your environment variables are not being loaded you won't be able to create a new SpotifyWebApi instance (check out dotenv file is not loading environment variables). Another easy way to check if this is the problem is to hard code your values temporarily.
Test your server /login endpoint independently before running the client to see whether the endpoint is returning 400 or another error when executing requests to Spotify.
Make sure you keep your devtools console open in your browser so you can identify any failed requests you're making to the Spotify API and consider setting devtools to preserve logs in case the page refreshing is deleting them.
If you are running both your client and server from inside VSCode, try instead running them both in new shells outside of VSCode.
I was having a similar issue, having followed this tutorial, and then this YouTube tutorial.
What I realised was that my App component was being rendered twice, which was causing everything to be called twice, including the login endpoint. I was able to verify this using console.log in the endpoint and seeing if the log appeared twice. As the same Spotify code was being used twice in SpotifyWebApi.authorizationCodeGrant, this was what was causing the error.
I was able to trace the issue to the React.StrictMode being enabled, which must have happened when using the create-react-app command. Verify whether the tags appear in your index.js file. For more information, check this StackOverflow answer: My React Component is rendering twice because of Strict Mode
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
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));
}