1

React seems to be messing with my session? The session data isn't being saved when I make requests via fetch, and this is the result:

Session {
  cookie:
   { path: '/',
     _expires: 2019-12-31T07:36:13.407Z,
     originalMaxAge: 7200000,
     httpOnly: true,
     sameSite: true,
     secure: false },
  user: { userId: '5ddc90090b5f01596e1450f4', username: 'Test' } }
::1 - - [Tue, 31 Dec 2019 05:36:13 GMT] "POST /api/session HTTP/1.1" 200 55 "http://localhost:3000/login" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"
Session {
  cookie:
   { path: '/',
     _expires: 2019-12-31T07:36:19.514Z,
     originalMaxAge: 7200000,
     httpOnly: true,
     sameSite: true,
     secure: false } }
::1 - - [Tue, 31 Dec 2019 05:36:19 GMT] "GET /api/session HTTP/1.1" 200 2 "http://localhost:3000/dashboard" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"

When I use Insomnia, everything is good:

Session {
  cookie:
   { path: '/',
     _expires: 2019-12-31T06:05:02.241Z,
     originalMaxAge: 7200000,
     httpOnly: true,
     secure: false,
     sameSite: true },
  user: { userId: '5ddc90090b5f01596e1450f4', username: 'Test' } }
::ffff:127.0.0.1 - - [Tue, 31 Dec 2019 05:40:21 GMT] "POST /api/session HTTP/1.1" 200 55 "-" "insomnia/7.0.5"
Session {
  cookie:
   { path: '/',
     _expires: 2019-12-31T06:05:02.241Z,
     originalMaxAge: 7200000,
     httpOnly: true,
     secure: false,
     sameSite: true },
  user: { userId: '5ddc90090b5f01596e1450f4', username: 'Test' } }
::ffff:127.0.0.1 - - [Tue, 31 Dec 2019 05:40:23 GMT] "GET /api/session HTTP/1.1" 200 64 "-" "insomnia/7.0.5"

See how the user persists in the session data? I don't know why it isn't happening in the requests with React.

This is my login page in React (to fire the POST request)

import React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { login } from "../actions/session";

const Login = ({ errors, login }) => {
  const handleSubmit = e => {
    e.preventDefault();
    const user = {
      email: e.target[0].value,
      password: e.target[1].value,
    };
    login(user);
  }  

  return (
    <>
      <h1>Login</h1>
      <p>{errors}</p>
      <form onSubmit={handleSubmit}>
        <label>
          Email:
          <input type="email" name="email" />
        </label>
        <label>
          Password:
          <input type="password" name="password" />
        </label>
        <input type="submit" value="Submit" />
      </form>
      <Link to="/signup">Signup</Link>
    </>
  );
};

const mapStateToProps = ({ errors }) => ({
  errors
});

const mapDispatchToProps = dispatch => ({
  login: user => dispatch(login(user))
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Login);

This is the action to dispatch:

export const login = user => async dispatch => {
  const response = await apiUtil.login(user);
  const data = await response.json();

  if (response.ok) {
    return dispatch(recieveCurrentUser(data));
  }

  return dispatch(receiveErrors(data));
}

This is how I'm making the request

export const login = user => (
  fetch("http://localhost:8080/api/session", {
    method: "POST",
    body: JSON.stringify(user),
    headers: {
      "Content-Type": "application/json"
    }
  })
);

This is the dashboard where I am fetching the data

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { logout, getUser } from '../actions/session';
import { getTransactions } from '../actions/transactions';

const uuid = require('uuid/v4');

class Dashboard extends Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    // this.props.getTransactions();
  };

  handleSubmit = () => {
    console.log("here");

    this.props.getUser();
  }

  render() {
    return (
      <div className="container">
        <h1>Hi {this.props.session.username}</h1>
        <p>You are now logged in!</p>
          {
            <div className="transactions">
            this.props.transactions.forEach(element => (
              <h1>element.title</h1>
              <p>element.uuid ? element.uuid : uuid()</p>
            ));
            </div>
          }
        <button onClick={this.props.logout}>Logout</button>
        <button onClick={this.handleSubmit}>Get Session Data</button>
        <p>{ this.props.session.username }</p>
      </div>
    );
  };
};

const mapStateToProps = ({ session, transactions }) => ({
  session,
  transactions
});

const mapDispatchToProps = dispatch => ({
  logout: () => dispatch(logout()),
  getUser: () => dispatch(getUser())
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Dashboard);

This is the request I am sending to do the GET request that gets the session data(in the button):

export const getData = () => (
  fetch("http://localhost:8080/api/session")
);

This is the action I am firing:

export const getUser = () => async dispatch => {
  const response = await apiUtil.getData();
  const data = await response.json();

  if (response.ok) {
    return dispatch(recieveCurrentUser(data));
  }
}
Bubblegum
  • 29
  • 2
  • 7

2 Answers2

2

Try in including credentials in your fetch:

export const login = user => (
  fetch("http://localhost:8080/api/session", {
    method: "POST",
    body: JSON.stringify(user),
    headers: {
      "Content-Type": "application/json"
    },
    credentials: 'include'
  })

);

Update

Of course, you've to enable the cors on the server side if you're not on the same domain...

You've to include the cors library provided by express.

Something like this :

app.use(cors({origin: 'localhost:3000', credentials:true }));
BENARD Patrick
  • 30,363
  • 16
  • 99
  • 105
  • When I do that, I can't send requests via the client anymore. I get ``` Access to fetch at 'http://localhost:8080/api/session' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. ``` – Bubblegum Jan 01 '20 at 01:48
  • @HardyAn Yep of course, I've updated the answer, look at the cors library... – BENARD Patrick Jan 01 '20 at 13:32
0

I assume when you mean Insomnia you're tallking about the HTTP debugger and also you're running your frontend code on some sort of react development server (e.g. webpack), if so it would most likely mean that your dev server is hosted on a different server (different port means different server in this context) from your backend. Since Insomnia is not a browser a lot of restrictions do not apply, one of them is that it's allowed to make requests to almost any server and read the response freely, this is not the case with your browser, to enable reading of responses 'complex' requests you need to pass some additional headers.

You can read about how to do it for fetch here

And about the header itself and the scenario here

Hopefully your server is configured to accept and respond to CORs if not you'll have to make the necessary changes.

steff_bdh
  • 1,108
  • 2
  • 15
  • 32