Skip to content

Commit

Permalink
feat: add support for cookie based login
Browse files Browse the repository at this point in the history
  • Loading branch information
iZooGooD committed Feb 12, 2024
1 parent bf1fc6b commit ef31ff8
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 16 deletions.
30 changes: 21 additions & 9 deletions server/controllers/User.controller.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import User from '../models/User.model.js';
import { validateUserInputs } from '../utils/validators.js';
import {
generateNewToken,
getToken,
validateToken,
} from '../utils/auth-helpers.js';
import { generateNewToken, validateToken } from '../utils/auth-helpers.js';
import bcrypt from 'bcrypt';
import { BCRYPT_CONFIG, USER_CREATION_MESSAGES } from '../utils/constants.js';
import {
BCRYPT_CONFIG,
USER_CREATION_MESSAGES,
HTTP_RESPONSE_COOKIE_CONFIG,
} from '../utils/constants.js';

export const registerUser = async (req, res) => {
try {
Expand Down Expand Up @@ -68,6 +68,10 @@ export const registerUser = async (req, res) => {
* @returns {Promise} A promise that resolves to the HTTP response with either a token or an error message.
*/
export const loginUser = async (req, res) => {
const cookieOptions = {
maxAge: HTTP_RESPONSE_COOKIE_CONFIG.MAX_AGE,
httpOnly: HTTP_RESPONSE_COOKIE_CONFIG.HTTP_ONLY,
};
try {
const { email, password } = req.body;
const user = await User.findOne({
Expand All @@ -77,16 +81,24 @@ export const loginUser = async (req, res) => {
});
bcrypt.compare(password, user.password, (err, result) => {
if (result && !err) {
// Check for existing token in the authorization header
const existingToken = getToken(req.headers.authorization);
// Check for existing cookie
const existingToken = req.cookies._token ?? '';
const isTokenValid = validateToken(existingToken);

if (existingToken && isTokenValid) {
res.cookie('_token', cookieOptions);
// If an existing token is valid, return it
return res.status(200).json({ token: existingToken });
return res.status(200).json({
data: {
token: existingToken,
},
errors: [],
});
} else {
// Generate a new token for the user - possibly the token is expired or its the first login attempt.
const token = generateNewToken(user);

res.cookie('_token', token, cookieOptions);
return res.status(200).json({
data: {
token,
Expand Down
14 changes: 8 additions & 6 deletions server/middlewares/auth.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getToken, validateToken } from '../utils/auth-helpers.js';
import { ERROR_MESSAGES } from '../utils/constants.js';
import { validateToken } from '../utils/auth-helpers.js';
import { JWT_ERROR_MESSAGES } from '../utils/constants.js';

/**
* Middleware to authenticate users based on the JWT token provided in the request headers.
Expand All @@ -17,18 +17,20 @@ import { ERROR_MESSAGES } from '../utils/constants.js';
* If the token is invalid, it responds with a 403 status code and an error message indicating that token validation failed.
*/
export const authUser = (req, res, next) => {
if (!req.headers.authorization) {
return res.status(401).json({ status: 'No credentials' });
if (!req.cookies._token) {
return res.status(401).json({ status: 'Please re-authenticate' });
} else {
const token = getToken(req.headers.authorization);
const token = req.cookies._token ?? '';
const isTokenValid = validateToken(token);
if (isTokenValid) {
req.user = {
id: isTokenValid.id,
};
return next();
} else {
return res.status(403).json({ status: ERROR_MESSAGES.JWT_GENERAL });
return res
.status(403)
.json({ status: JWT_ERROR_MESSAGES.JWT_GENERAL });
}
}
};
10 changes: 9 additions & 1 deletion server/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ export const USER_CREATION_MESSAGES = Object.freeze({
/**
* A collection of error messages related to JWT authentication.
*/
export const ERROR_MESSAGES = Object.freeze({
export const JWT_ERROR_MESSAGES = Object.freeze({
JWT_GENERAL: 'Validation of token failed',
});

/**
* Config for response cookie when user authenticates on /login route.
*/
export const HTTP_RESPONSE_COOKIE_CONFIG = Object.freeze({
MAX_AGE: 1000 * 60 * 15, // would expire after 15 minutes
HTTP_ONLY: true,
});

0 comments on commit ef31ff8

Please sign in to comment.