score:8

Accepted answer

you don't need to store another cookie. i suppose you use token based authentication on your endpoint, eg. jwt. then you think about this scenario:

  1. user send username/password to server.
  2. check user credentials and if there are valid, create http-only cookie with the token
    const user = await getuser({ where: { email } });

    const valid = await bcrypt.compare(password, user.password);
    if (!valid) {
      throw new userinputerror('form arguments invalid', {
        invalidargs: {
          'password': 'invalid password!',
        },
      });
    }

    const token = jwt.sign({ userid: user.id }, process.env.app_secret);
    /
    res.cookie('token', token, {
      httponly: true,
      maxage: 1000 * 60 * 60 * 24 * 365,
    });

  1. write auth middlerware to put the userid onto the req for future requests to access
const jwt = require('jsonwebtoken');
const { authenticationerror } = require('apollo-server');

module.exports = async function(req, res, next) {
  const { token } = req.cookies;

  if (token) {
    try {
      const { userid } = jwt.verify(token, process.env.app_secret);

      if (!userid) return next();
      req.userid = userid;

    } catch (e) {
      console.log(e);
    }
  }

  next();
};
  1. check on each request the userid. if there is no userid, user doesn't logged in
  if (!req.userid) {
     throw new authenticationerror('log in!');
   }
  1. if user's token is invalid/expired you will get authenticationerror. catch it and redirect to login page.
  2. if your ui depends on user status, you can create easy-to-use component (i am using react) to check it.

user component:

import { query } from 'react-apollo';
import gql from 'graphql-tag';
import proptypes from 'prop-types';

const current_user_query = gql`
  query current_user_query {
    me {
      userid
      firstname
      lastname
      profilepictureurl
    }
  }
`;

const user = props => (
  <query {...props} query={current_user_query} fetchpolicy={'cache-first'}>
    {payload => props.children(payload)}
  </query>
);

user.proptypes = {
  children: proptypes.func.isrequired,
};

export default user;

if we get me object from server, you know, there is a logged in user, so you can render depends on user's status:

import { link } from 'react-router-dom';
import react from 'react';

<user>
  {({ loading, error, data: { me } }) => {
    if (loading || error || !me) return (
      <button component={link} to={'/login'}>login</button>
    );
    if(me) return (
      <button component={link} to={'/dashboard'}>go to dashboard</button>
    )
  }}
</user>

Related Query

More Query from same tag