最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Express + React: CSRF Cookie is undefined in production, works locally - Stack Overflow

programmeradmin0浏览0评论

I'm hosting my express API on Heroku and my client on Netlify. When I try my signup route locally, my cookie is defined and the route works. However, when it is in production, the cookie always returns undefined and my API times out.

Note that the cookie is being sent successfully from the backend. I’m able to view it in Dev Tools. Additionally, cookies,get() returns an empty object.

I’m using Js-cookie.

I'm using js-cookie in Gatsby. I'm using CSURF in express for the cookie.

Backend:

//CSURF Config
app.use(csurf({ cookie: true }));


//Route that generates CSRF Cookie
app.get("/getToken", (req, res) => {
    res.cookie("XSRF-TOKEN", req.csrfToken());
    res.end();
  });

Frontend:

I'm including the entire sign up function. Note that this is two end point calls, one to retrieve the cookie, and one to create user record.

  userSignUp = async (email, password, resetForm) => {
    console.log("THis is a test of the emergency..")
    await fetch(process.env.API + "getToken", {
      mode: "cors", // no-cors, cors, *include
      cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
      credentials: "include", // include, *include, omit
      headers: {
        "content-type": "application/json",
      },
      method: "GET",
    })
    const token = Cookies.get("XSRF-TOKEN")
    alert(Cookies.get("XSRF-TOKEN"))
    const data = await fetch(process.env.API + "signUp", {
      body: JSON.stringify({ email: email, password: password }),
      mode: "cors", // no-cors, cors, *include
      cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
      credentials: "include", // include, *include, omit
      headers: {
        "content-type": "application/json",
        "csrf-token": token,
      },
      method: "POST",
    }).catch(error => this.setState({ isError: true }))
    if (data.ok) {
      console.log(data.ok)
      data.json().then(content => {
        console.log(content)
        this.props.changeAuth(content.authStatus)
        this.props.setCategories(content.user.categories)
        this.props.getEvents(content.user.events)
        resetForm()
      })
    } else {
      this.setState({
        isError: true,
      })
    }
  }

I'm hosting my express API on Heroku and my client on Netlify. When I try my signup route locally, my cookie is defined and the route works. However, when it is in production, the cookie always returns undefined and my API times out.

Note that the cookie is being sent successfully from the backend. I’m able to view it in Dev Tools. Additionally, cookies,get() returns an empty object.

I’m using Js-cookie.

I'm using js-cookie in Gatsby. I'm using CSURF in express for the cookie.

Backend:

//CSURF Config
app.use(csurf({ cookie: true }));


//Route that generates CSRF Cookie
app.get("/getToken", (req, res) => {
    res.cookie("XSRF-TOKEN", req.csrfToken());
    res.end();
  });

Frontend:

I'm including the entire sign up function. Note that this is two end point calls, one to retrieve the cookie, and one to create user record.

  userSignUp = async (email, password, resetForm) => {
    console.log("THis is a test of the emergency..")
    await fetch(process.env.API + "getToken", {
      mode: "cors", // no-cors, cors, *include
      cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
      credentials: "include", // include, *include, omit
      headers: {
        "content-type": "application/json",
      },
      method: "GET",
    })
    const token = Cookies.get("XSRF-TOKEN")
    alert(Cookies.get("XSRF-TOKEN"))
    const data = await fetch(process.env.API + "signUp", {
      body: JSON.stringify({ email: email, password: password }),
      mode: "cors", // no-cors, cors, *include
      cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
      credentials: "include", // include, *include, omit
      headers: {
        "content-type": "application/json",
        "csrf-token": token,
      },
      method: "POST",
    }).catch(error => this.setState({ isError: true }))
    if (data.ok) {
      console.log(data.ok)
      data.json().then(content => {
        console.log(content)
        this.props.changeAuth(content.authStatus)
        this.props.setCategories(content.user.categories)
        this.props.getEvents(content.user.events)
        resetForm()
      })
    } else {
      this.setState({
        isError: true,
      })
    }
  }
Share Improve this question edited Dec 28, 2019 at 23:35 sideshowbarker 88.4k29 gold badges215 silver badges212 bronze badges asked Dec 10, 2019 at 1:25 WriterStateWriterState 3694 silver badges20 bronze badges 2
  • 1 What is your webpage URL, and your server URL? – Roy Wang Commented Dec 12, 2019 at 7:05
  • they are different... One is a heroku random url the other is a netlify url Note that it worked on local host port 3000(server) and local host port 8000(client). And also that the cookies are being set by the server. I can see them in chrome dev tools. – WriterState Commented Dec 12, 2019 at 23:02
Add a ment  | 

2 Answers 2

Reset to default 8 +25

The cookies will not work if the front-end and server domains are different.

You can set up a proxy through Netlify to redirect all requests to a path (eg. /api/) of the front-end domain to the backend domain.

To set up the proxy, you can create a _redirects file in the publish directory (eg. public) with the following configuration:

/api/*  https://<server-url>:<server-port>/:splat 200

Lastly, send all HTTP requests to that front-end path (eg. https://<front-end-url>/api/users) instead of the backend URL to ensure that the cookies work correctly.

...when it is in production, the cookie always returns undefined...

One possible reason could be that you are using HTTPS in production (which should be the case) and the browser ignores the CSRF cookie because it is not set as a secure cookie. To fix this issue use secure cookies in production and non-secure ones in development.

P.S.
To make the first cookie to be secure replace this code

app.use(csurf({ cookie: true }));

with that:

app.use(csurf({
  cookie: {
    httpOnly: true,
    secure: !devModeFlag
  }
}));

The httpOnly setting ensures JS on the client cannot touch this cookie which is good for extra security. The boolean devModeFlag variable should be set to true in development and to false in production.

To make the second cookie to be secure replace this code

res.cookie("XSRF-TOKEN", req.csrfToken());

with that:

res.cookie("XSRF-TOKEN", req.csrfToken(), { secure: !devModeFlag });
发布评论

评论列表(0)

  1. 暂无评论