Wednesday 26 April 2017

Node API on Heroku sends set-cookie headers, but Chrome won't set them (Postman, however, will)

I made a completely stripped down test API and frontend to demonstrate this issue, which will take place when at least the API is deployed to Heroku:

This is the whole API. app.js:

const express = require('express')
const cors = require('cors')
const app = express()
const router = express.Router()

// This was supposed to help with problems from Heroku's Vegur
// I also tried app.enable('trust proxy') syntax
app.set('trust proxy', true) 

// allow cors
const corsOptions = {
  'origin': true,
  'credentials': true,
}
app.options('*', cors(corsOptions))
app.use(cors(corsOptions))

const port = process.env.PORT || 3000

app.use(router)

router.get('/', function (req, res) {
  res.send('test ready')
})

router.post('/', function (req, res) {
  res.cookie("testCookie", {
      led: "zepplin",
      pink: "floyd",
    }, {
      encode: String
    })
  res.send("cookie set")
})

app.listen(port, () => {
  console.log(`listening on port ${port}`)
})

package.json:

{
  "name": "testapp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node app.js",
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.3",
    "express": "^4.15.2"
  }
}

And this is the entire frontend. A php one-liner to make it go, index.php:

<?php header( 'Location: /index.html' ) ;  ?>

And index.html:

<!DOCTYPE html>
<html>
  <head>
    <script>

      function fetchAPI() {
        fetch(your_heroku_api_url, {
          method: 'POST',
          credentials: 'include',
        })
        .then((response) => {
          return response.text()
        })
        .then((text) => {
          console.log({res: text})
        })
        .catch((er) => {
          console.log({error: er})
        })
      }

    </script>
  </head>
  <body>
    <button onclick=fetchAPI()>FETCH REQUEST</button>
  </body>
</html>

If I hit that POST route with Postman, I get the intended behavior. The cookies will be set. If I do so from Chrome. I do not. I do get the set-cookie header, but Chrome will not set that cookie:

chrome dev tool network tab

So I'm pretty stuck. I have an auth token implemented similar to this in a more complex app suffering from the same issue. It just uses Express's res.cookie() method like above, it also arrives at the browser, it will also be ignored. Further I have my sessions set up with client-sessions. Those cookies exhibit the same unsuccessful behavior. Occasionally, I will even see the cookie sent in the request and I have no idea how that is happening since it is never being set in the browser. Again there, everything will work when run locally on separate ports or if the local or Heroku API is accessed by Postman.



via TheRealWinnebagoMan

No comments:

Post a Comment