👋 Enjoying the content? Subscribe to our Medium publication for more articles like this. 👇
Keep Learning

Nodejs JWT Authentication With HTTP Only Cookie

BY Atakan Demircioğlu
Table of Contents

What is HTTP Only Cookie?

Nodejs JWT Authentication With HTTP Only Cookie image 1

What is HTTP Only Cookie?

What is JWT? (JSON Web Token)

Real Word Node.js Application

Let's assume you have a basic login page and you are sending a username and password to an endpoint named as /auth or etc.

import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { PrismaClient } from '@prisma/client';
import HTTPMethod from 'http-method-enum';
import HTTP_STATUS_CODES from 'http-status-enum';
import { serialize } from 'cookie';
const prisma = new PrismaClient();
const KEY = process.env.JWT_KEY;
export default async function authenticate(req, res) {
  const { method } = req;
  try {
    switch (method) {
      case HTTPMethod.POST:
        
        const { email, password } = req.body;
        if (!email || !password) {
          return res.status(HTTP_STATUS_CODES.BAD_REQUEST).json({
            status: 'error',
            error: 'Request missing email or password',
          });
        }
        const user = await prisma.user.findUnique({
          where: {
            email: email,
          },
        });
        if (!user) {
          return res
            .status(HTTP_STATUS_CODES.BAD_REQUEST)
            .json({ status: 'error', error: 'User Not Found' });
        }
        bcrypt.compare(password, user.password).then((isMatch) => {
          if (isMatch) {
            const payload = {
              id: user.id,
              email: user.email,
              createdAt: user.createdAt,
              username: user.username,
              fullname: user.fullname,
            };
            jwt.sign(
              payload,
              KEY,
              {
                expiresIn: 60 * 60 * 24 * 30,
              },
              (_err, token) => {
                const serialized = serialize('token', token, {
                  httpOnly: true,
                  secure: process.env.NODE_ENV === 'production',
                  sameSite: 'strict',
                  maxAge: 60 * 60 * 24 * 30,
                  path: '/',
                });
                res.setHeader('Set-Cookie', serialized);
                res.status(HTTP_STATUS_CODES.OK).json({
                  success: true,
                  user: {
                    email: payload.email,
                    username: payload.username,
                    fullname: payload.fullname,
                  },
                });
              },
            );
          } else {
            res.status(HTTP_STATUS_CODES.BAD_REQUEST).json({
              status: 'error',
              error: 'Password and email does not match.',
            });
          }
        });
        break;
    }
  } catch (error) {
    console.log(error);
    res.status(HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR).json({
      status: 'error',
      error: 'Internal Server Error',
    });
  }
}

So how about the logout process?

import { serialize } from 'cookie';
export default function logout(req, res) {
  const { cookies } = req;
  const jwt = cookies.token;
  if (!jwt) {
    return res.status(401).json({
      status: 'error',
      error: 'Unauthorized',
    });
  }
  const serialized = serialize('token', null, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict',
    maxAge: -1,
    path: '/',
  });
  res.setHeader('Set-Cookie', serialized);
  res.status(200).json({
    status: 'success',
    message: 'Logged out',
  });
}

It is a little different but the logic is the same. We just need an endpoint like /logout and just need to set up maxAge -1 or just 0.

I just tried to explain the logic with a basic example. You can improve the security part or the logic whatever you want.

You can also my article about the usage of next-js middleware.

References

Check these articles:

javascript nodejs