-1

I've stumbled upon a problem whilst developing my app and I am now stuck. My web app is a very simple interface for registering/logging/modifying users using MERN stack along with Redux and Axios. While calling /update endpoint like so:

export const updateUser = (userData, history) => dispatch => {
    let token = localStorage.getItem("jwtToken");
    axios.defaults.headers.common["Authorization"] = token;
    console.log(token);
    axios
        .patch('http://localhost:5000/api/users/update', userData, { crossdomain: true })
        .then(res => {
            history.push("/dashboard");
        })
        .catch(err =>
            dispatch({
                type: GET_ERRORS,
                payload: err.response.data
            })
        );
};

However, I keep getting cors authorization error( "missing authorization token in CORS header „Access-Control-Allow-Headers” in CORS OPTIONS request" ), although in the above code you can clearly see I;m setting it explicitly (I set it even one more time earlier, just after user login).

I had similar CORS issues previously with login/register post requests, but they were fixed when I added in the backend:

router.use(function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "http://localhost:3000");
    res.header("Access-Control-Allow-Methods", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});

Shouldn't I have the same problem earlier, when calling the database with login/register post requests? The assigned token is not empty and all the endpoints work fine when tested with Postman. I've run out of ideas what to do.

This is the calling component:

import React, { Component } from "react";
import { Link, withRouter } from "react-router-dom";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { updateUser } from "../actions/authActions";
import { deleteUser } from "../actions/authActions";
import classnames from "classnames";

class DataChange extends Component {
    constructor() {
        super();
        this.state = {
            name: "",
            email: "",
            password: "",
            password2: "",
            errors: {}
        };
    }


    UNSAFE_componentWillReceiveProps(nextProps) {
        if (nextProps.errors) {
            this.setState({
                errors: nextProps.errors
            });
        }
    }

    onChange = e => {
        this.setState({ [e.target.id]: e.target.value });
    };

    onDeleteClick = e =>{
        e.preventDefault();
        this.props.deleteUser(this.props.auth.user.id);
    }

    onSubmit = e => {
        e.preventDefault();
        const newUser = {
            id: this.props.auth.user.id,
            name: this.state.name,
            email: this.state.email,
            password: this.state.password,
            password2: this.state.password2
        };
        console.log(newUser);
        this.props.updateUser(newUser, this.props.history);
    };

    render() {
        const { errors } = this.state; return (
            <div className="container">
                <div className="row">
                    <div className="col s8 offset-s2">
                        <Link to="/dashboard" className="btn-flat waves-effect">
                            <i className="material-icons left">keyboard_backspace</i> Back to
                            home
            </Link>
                        <div className="col s12" style={{ paddingLeft: "11.250px" }}>
                            <h4>
                                <b>Zmień</b> dane
              </h4>

                        </div>
                        <form noValidate onSubmit={this.onSubmit}>
                            <div className="input-field col s12">
                                <input
                                    onChange={this.onChange}
                                    value={this.state.name}
                                    error={errors.name}
                                    id="name"
                                    type="text"
                                    className={classnames("", {
                                        invalid: errors.name
                                    })}
                                />
                                <label htmlFor="name">Name</label>
                                <span className="red-text">{errors.name}</span>
                            </div>
                            <div className="input-field col s12">
                                <input
                                    onChange={this.onChange}
                                    value={this.state.email}
                                    error={errors.email}
                                    id="email"
                                    type="email"
                                    className={classnames("", {
                                        invalid: errors.email
                                    })}
                                />
                                <label htmlFor="email">Email</label>
                                <span className="red-text">{errors.email}</span>
                            </div>
                            <div className="input-field col s12">
                                <input
                                    onChange={this.onChange}
                                    value={this.state.password}
                                    error={errors.password}
                                    id="password"
                                    type="password"
                                    className={classnames("", {
                                        invalid: errors.password
                                    })}
                                />
                                <label htmlFor="password">Password</label>
                                <span className="red-text">{errors.password}</span>
                            </div>
                            <div className="input-field col s12">
                                <input
                                    onChange={this.onChange}
                                    value={this.state.password2}
                                    error={errors.password2}
                                    id="password2"
                                    type="password"
                                    className={classnames("", {
                                        invalid: errors.password2
                                    })}
                                />
                                <label htmlFor="password2">Confirm Password</label>
                                <span className="red-text">{errors.password2}</span>
                            </div>
                            <div className="col s6" style={{ paddingLeft: "11.250px" }}>
                                <button
                                    style={{
                                        width: "150px",
                                        borderRadius: "3px",
                                        letterSpacing: "1.5px",
                                        marginTop: "1rem"
                                    }}
                                    type="submit"
                                    className="btn btn-large waves-effect waves-light hoverable blue accent-3"
                                >
                                    Wprowadź zmiany
                                </button>
                            </div>

                            <div className="col s6" style={{ paddingLeft: "11.250px" }}>
                                <button
                                    style={{
                                        width: "150px",
                                        borderRadius: "3px",
                                        letterSpacing: "1.5px",
                                        marginTop: "1rem"
                                    }}
                                    onClick={this.onDeleteClick}
                                    className="btn btn-large waves-effect waves-light hoverable red accent-3"
                                >
                                    Usuń użytkownika
                                </button>
                            </div>

                        </form>
                    </div>
                </div>
            </div>
        );
    }
}

DataChange.propTypes = {
    updateUser: PropTypes.func.isRequired,
    auth: PropTypes.object.isRequired,
    errors: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
    auth: state.auth,
    errors: state.errors
});

const mapDispatchToProps = {
    deleteUser,
    updateUser,
};

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(withRouter(DataChange));
halfer
  • 18,701
  • 13
  • 79
  • 158
nfsu
  • 61
  • 1
  • 9
  • Can you trace your request in browser's developer tools Network tab? Do you see the Authorization header with token in the request headers? – SuleymanSah Jan 29 '20 at 06:31

2 Answers2

2

In the express app, you need to add Authorization to the Access-Control-Allow-Headers. Also you can use * for Access-Control-Allow-Origin to get rid of origin problems.

router.use(function (req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "*");
  res.header("Access-Control-Allow-Headers", 
             "Origin, X-Requested-With, Content-Type, Accept, Authorization");
  next();
});
SuleymanSah
  • 13,055
  • 5
  • 17
  • 42
0
router.use(function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Methods", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});

Can you try replacing this ? If you want to do for only one domain, follow this answer - Access-Control-Allow-Origin Multiple Origin Domains?

Krina Soni
  • 722
  • 5
  • 12