Node.js · Mongoose · Authentication

Implementing Access and Refresh Tokens with Mongoose Methods

Implement access and refresh tokens in Node.js with reusable Mongoose methods.

Implementing Access and Refresh Tokens with Mongoose Methods article thumbnail

Table of Contents

Overview

In modern web applications, managing user authentication is essential for security and user experience. Access and refresh tokens are two key components of this system.

Access Tokens

These are short-lived tokens used to authenticate users and authorize access to protected resources. Typically valid for a limited time (e.g., 1 hour), they help ensure that user sessions remain secure.

Refresh Tokens

In contrast, refresh tokens have a longer lifespan (e.g., 7 days). They are used to obtain new access tokens once the current ones expire. This two-token system minimizes risk; if an access token is compromised, its short validity limits exposure, while refresh tokens can be revoked if necessary.

Note: Make sure you have the database setup completed before proceeding.

User Schema Method for Token Generation

First, let's create the user schema to include methods for generating access and refresh tokens.

import mongoose from 'mongoose';
import jwt from 'jsonwebtoken';
 
const userSchema = new mongoose.Schema({
  username: { type: String, required: true, unique: true },
  password: { type: String, required: true },
  refreshToken: { type: String },
});
 
// Methods for token generation
userSchema.methods.generateAccessToken = function () {
  return jwt.sign(
    { _id: this._id, username: this.username },
    process.env.ACCESS_TOKEN_SECRET || "access-token-secret",
    { expiresIn: "1h" } // Token valid for 1 hour
  );
};
 
userSchema.methods.generateRefreshToken = function () {
  return jwt.sign(
    { _id: this._id, username: this.username },
    process.env.REFRESH_TOKEN_SECRET || "refresh-token-secret",
    { expiresIn: "7d" } // Token valid for 7 days
  );
};
 
const User = mongoose.model('User', userSchema);
export default User;

Login Route with Token Creation

Next, let's implement the login route to generate and save both access and refresh tokens.

import express from 'express';
import bcrypt from 'bcryptjs';
import mongoose from 'mongoose';
import User from './models/User.js'; // Adjust the path as needed
 
const router = express.Router();
 
// Connect to the database
mongoose.connect(process.env.MONGO_URI || "your-mongo-db-uri", {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});
 
// Login route
router.post('/login', async (req, res) => {
  const { username, password } = req.body;
  try {
    // Mongoose methods for DB query are accessed using User
    const user = await User.findOne({ username });
    if (!user || !(await bcrypt.compare(password, user.password))) {
      return res.status(400).json({ message: 'Invalid credentials' });
    }
 
    // Generate tokens
    const accessToken = user.generateAccessToken(); // Access user instance method
    const refreshToken = user.generateRefreshToken();
 
    // Save refresh token in the database
    user.refreshToken = refreshToken;
    await user.save(); // Save user with new refresh token
 
    res.json({ accessToken, refreshToken });
  } catch (error) {
    res.status(500).json({ message: 'Server error' });
  }
});
 
export default router;

Summary

In this implementation:

  • Access and refresh tokens are generated using methods defined in the user schema.
  • The login route checks user credentials and, upon successful authentication, creates and saves the tokens.
  • The refresh token is stored in the database for future validation.

This setup allows you to manage user sessions securely with Mongoose and JWT using ES6 module syntax.

Happy Coding! 🚀