0

I'm trying to reset password using React and Redux. I got an url to email address and when I paste it into browser everything is fine - site with fields to input new password is rendering. The problem is when I want to set new password. Response from Django server is 200 OK but I have this error in the browser after submit:

Access to XMLHttpRequest at 'http://127.0.0.1:8000/password-reset/confirm/' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field token is not allowed by Access-Control-Allow-Headers in preflight response.

My password.js file in actions directory (Redux):

export const resetPassword = (password, token) => (dispatch, getState) => {

  // Headers
  const config = {
    headers: {
      'Content-Type': "application/json",
      token
    },
  }

  const body = JSON.stringify({ password })

  // Post request to API
  axios.post('http://127.0.0.1:8000/password-reset/confirm/', body, config)
  .then(res => {
    console.log(res);
     dispatch({
      type: RESET_PASSWORD,
      payload: res.data
    })
  })
  .catch(err => {
    console.log(err.response.status);
  })
}

NewPasswordPage.js:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { resetPassword } from '../actions/password';

class NewPasswordPage extends Component {
  state = {  
    password: '',
    token: ''
  }

  static propTypes = {
    resetPassword: PropTypes.func.isRequired,
  }

  handleChange = e => {
    this.setState({ [e.target.name]: e.target.value })
    console.log(this.state);
  }

  handleSubmit = e => {
    e.preventDefault();
    console.log("OK NEW PASSWORD")

    const { password, token } = this.state;

    this.props.resetPassword(password, token)
  }

  render() { 
    return (  
      <div className="col-md-6 m-auto">
        <div className="card card-body mt-5">
          <h2 className="text-center">New password</h2>
          <form onSubmit={this.handleSubmit}>
            <div className="form-group">
              <label>New password</label>
                <input
                  type="password"
                  className="form-control"
                  name="password"
                  onChange={this.handleChange}
                  value={this.state.password}
                />
            </div>
            <div className="form-group">
              <label>Token</label>
                <input
                  type="text"
                  className="form-control"
                  name="token"
                  onChange={this.handleChange}
                  value={this.state.token}
                />
            </div>
            <div className="form-group">
              <button type="submit" className="btn btn-primary">Submit</button>
            </div>
          </form>
        </div>
      </div>
    );
  }
}

const mapStateToProps = state => ({
  resetPassword: state.password
})
 
export default connect(mapStateToProps, { resetPassword })(NewPasswordPage);

At this time I am trying to solve the problem and just paste the token in input. I don't know how to get the token from url - if you have any idea that would be great.

URL:

http://localhost:3000/password-reset/5e570e6856cbe8a935f06f8f52

Endpoint in App.js:

<Route path='/password-reset/:token' component={NewPasswordPage} />
adn98
  • 193
  • 2
  • 4
  • 12

2 Answers2

0

The issue is due to CORS. The hostname 127.0.0.1:8000 is different than localhost:3000. When the hostnames are different then the a CORS error is thrown by default. This is a browser security feature to prevent malicious attacks from different domains spooging API requests. To fix the error you need to disable CORS. This will allow 27.0.0.1 to communicate with localhost

TO enable CORS on a django server: How can I enable CORS on Django REST Framework

If you are running an express and a node end-point: https://expressjs.com/en/resources/middleware/cors.html

It sounds like you either need to enable CORS on the server or make sure that the correct access control header is set. Within Django somewhere

Access-Control-Allow-Headers: *
Jon Jones
  • 1,014
  • 1
  • 9
  • 17
  • Thank you for your answer. Actually I had this problem some time ago when I was trying to implement login and register functionality. I changed this settings with CORS then and my login and register is all right, but I have that error again in reset password. Is there any other case why I got this? – adn98 Jun 23 '20 at 20:22
  • The issue will be somewhere on the server. YOu may need to enable some extra configuration. Have a look at: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers Access-Control-Allow-Headers: * – Jon Jones Jun 24 '20 at 13:22
0

Try changing the ip 27.0.0.1:8000 to localhost:8000.

You dont have to set the token in the state as it is not going to change inside the state.

handleSubmit = e => {
 e.preventDefault();
 console.log("OK NEW PASSWORD")

 const { password } = this.state;

 this.props.resetPassword(password, this.props.match.params.token);
}

To receive the path param in you component, you need to connect your component with withRouter HOC from react-router so that you can access the Router props and get the path params from the match props as this.props.match.params.token.

const NewPasswordPage = connect(
 mapStateToProps,
 mapDispatchToProps
)(NewPasswordView);

export default withRouter(NewPasswordPage);
Jagan
  • 590
  • 1
  • 8
  • 21
  • It doesn't work. I can't do "const NewPasswordPage" because this name is already taken. And I don't understand what is NewPasswordView – adn98 Jun 23 '20 at 21:33
  • Change your class name to NewPasswordView – Jagan Jun 23 '20 at 21:37
  • Ok right now it is much better I think but response from the server is 400 (Bad Request) and in my browser console i have `data: token: ["This field is required."]`. Any ideas what's wrong? – adn98 Jun 23 '20 at 22:01
  • DId you get the token by this.props.match.params.token? check in browser request that your request is in correct form. Or just post your axios code and api code so people can understant what going wrong – Jagan Jun 23 '20 at 22:08
  • Yes I got token by this.props.match.params.token and when I try to console.log it in console that's fine. I pass token and password into the resetPassword function but I think that server doesn't see that token because I get `{data: {token: ["This field is required"]}}` and 400 (Bad Request Error). In data object in my response from browser I have `{data: "{"password":"examplepassword"}"}` – adn98 Jun 23 '20 at 22:53
  • Then this is something on your server side code. It can only be resolved if you post your server side code. though you are passing the token in request header and password in body please check on your api resource code that you are expecting the inputs in same way – Jagan Jun 23 '20 at 23:03
  • Yes I changed it and I get this error when I pass token and password in body as my server requires – adn98 Jun 24 '20 at 01:23
  • 1
    I am sorry dude can't understand whats your problem in the API, Create a new Question with your server side code and axios code. As my answer fullfill your url path param and cross-origin issue, You could make this answer correct and upvote. – Jagan Jun 24 '20 at 01:30