'Client doesnt get cookie from my node.js api

I have made an authentication with jwt api in node.js/express and i run it on heroku. When a user logged in, server create a cookie via cookie-parser and send it to the client. Below is the code from server.js

const express = require('express');
const jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser');
const cors = require('cors');
const path = require('path');
const bcrypt = require('bcrypt');
const PORT = process.env.PORT || 3000;
const serveStatic = require('serve-static');
require('dotenv').config();
const mongoose = require('mongoose');
const { User, Posts } = require(path.join(__dirname, './model.js'));
const mongoString = process.env.DATABASE_URL;
const JWT_SECRET = process.env.JWT_SECRET;
const { verifyToken, checkUser } = require(path.join(__dirname, './auth.js'));

const app = express();

//Middlewares
app.use(
  cors({
    credentials: true,
    origin: true,
  })
);
app.use(express.json());
app.use(cookieParser());

//Connect to Database
mongoose.connect(mongoString);
const db = mongoose.connection;
db.on('error', (err) => {
  console.log(err);
});
db.once('connected', () => {
  console.log('----Database Connected----\n');
});

//functions
const maxAge = 3 * 24 * 60 * 60;
const createToken = (id) => {
  return jwt.sign({ id }, JWT_SECRET, {
    expiresIn: maxAge,
  });
};

// AUTH ROUTES
app.get('*', checkUser);
app.get('/', checkUser, (req, res) => {
  res.json({ status: 'success' });
});

app.post('/api/register', async (req, res) => {
  const salt = await bcrypt.genSalt();
  try {
    const user = await User.create(
      new User({
        username: req.body.username,
        email: req.body.email,
        city: req.body.city,
        password: await bcrypt.hash(req.body.password, salt),
      })
    );
    const token = createToken(user._id);
    res.cookie('jwt', token, {
      maxAge: maxAge * 1000,
      secure: true,
    });
    res.status(201).json(user);
    console.log(user);
  } catch (err) {
    console.log(err);
    res.json(err);
  }
});

app.post('/api/login', async (req, res) => {
  try {
    const { email, password } = req.body;
    const user = await User.findOne({ email }).lean();
    if (!user) {
      return res.send({
        status: 'error',
        error: 'Invalid email',
      });
    }
    if (await bcrypt.compare(password, user.password)) {
      const token = createToken(user._id);
      res.cookie('jwt', token, { secure: true, maxAge: maxAge * 1000 });
      res.status(200).send({ status: 'ok', token: token });
      console.log(user._id + ' logged in successfully');
      return;
    }
    return res.send({ status: 'error', error: 'Invalid password' });
  } catch (err) {
    console.log(err);
  }
});

app.get('/api/home', verifyToken, (req, res) => {
  res.send(res.locals.user);
});

app.get('/api/logout', (req, res) => {
  try {
    res.cookie('jwt', '', { maxAge: 1 });
    res.status(200).send({ status: 'ok' });
  } catch (err) {
    res.send(err);
  }
});

//POSTS ROUTES
app.post('/api/posts', verifyToken, checkUser, async (req, res) => {
  try {
    const post = await Posts.create(
      new Posts({
        postBody: req.body.postBody,
        city: req.body.city,
        author: res.locals.user.id,
      })
    );
    res.status(200).json(post);
    console.log('====New Post=====');
  } catch (err) {
    res.status(400).send({ message: err.message });
  }
});

app.get('/api/posts', verifyToken, async (req, res) => {
  try {
    const data = await Posts.find();
    res.send({ user: res.locals.user, data: data });
  } catch (err) {
    res.json({ message: err.message });
  }
});

app.get('/api/posts/:city', verifyToken, async (req, res) => {
  try {
    const data = await Posts.find({ city: req.params.city });
    res.json(data);
    res.send(res.locals.user);
  } catch (err) {
    res.json({ message: err.message });
  }
});

//run server
app.listen(PORT, () => {
  console.log(`Server running on ${PORT}...\n`);
});

Now, for front-end i use Vue.js that its running on Firebase.

Here is the script part of Login.Vue

<script>
/* eslint-disable */
import axios from 'axios';

export default {
  name: 'Login',
  data() {
    return {
      email: '',
      password: '',
      error: '',
    };
  },
  methods: {
    async onSubmit() {
      if (!this.email || this.password.length < 6) {
        this.error = 'vale kati';
        return;
      }
      await axios
        .post(
          'https://thelostpet.herokuapp.com/api/login',
          {
            email: this.email,
            password: this.password,
          },
          { withCredentials: true }
        )
        .then((res) => {
          console.log(res.data.token);
          if (res.data.status == 'error') {
            this.error = res.data.error;
          }
          if (res.data.status == 'ok') {
            this.$router.push('/home');
          }
        })
        .catch((err) => {
          console.log(err);
        });
    },
  },
};
</script>

When I try to login from Login.vue, that its ruuning on Firebase, the browser doesn't save the cookie that it created from the api.

BUT when I make a post request on https://thelostpet.herokuapp.com/api/login from postman, the cookie is saved on postman.

Thank you!



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source