1.0.4 • Published 3 years ago

node-mongoose-auth v1.0.4

Weekly downloads
-
License
MIT
Repository
github
Last release
3 years ago

node-mongoose-auth

Small package for handling user authentication in node + express + mongoose applications using TOKEN AUTHENTICATION

Installation

npm install --save node-mongoose-auth

Configuration

The package expects the developer to set the: 1. SECRET_KEY environment variable. You can do this in your .env file and use dotenv package to load it with

```js
require("dotenv").config();
```
Or you can add it your bash profile, load it from a config file, whichever method you use should work just fine.
  1. TOKEN_EXPIRES_AFTER: Number of days for token validity. By default this is set to 1 ( 24 hours ). NB: If in prodution and SECRET_KEY is missing, the node process will be terminated!

Usage

const express = require("express");
const { authRouter } = require("node-mongoose-auth");

const app = express();

app.use(express.json())
app.use("/api/auth", authRouter);

Endpoints

  1. POST /api/auth/register
  2. POST /api/auth/login
  3. GET /api/auth/getuser

Schema

node-mongoose-auth creates a user model with the following schema.

const UserSchema = mongoose.Schema(
  {
    firstName: {
      type: String,
      required: true,
      max: 25,
    },
    lastName: {
      type: String,
      required: true,
      max: 25,
    },
    email: {
      type: String,
      trim: true,
      lowercase: true,
      required: true,
      unique: true,
      validate: [validateEmail, "Please provide a valid email address"],
    },
    mobile: {
      type: String,
      required: false,
      min: 10,
      max: 15,
    },
    address: {
      type: String,
      required: false,
      max: 100,
    },
    birthDate: {
      type: Date,
      required: false,
    },
    sex: {
      type: String,
      enum: ["Male", "Female"],
      required: true,
    },
    about: {
      type: String,
      required: false,
    },
    hash: {
      type: String,
      required: false,
    },
    salt: {
      type: String,
      required: false,
    },
    isActive: {
      type: Boolean,
      default: true,
    },
    isStaff: {
      type: Boolean,
      default: false,
    },
    isAdmin: {
      type: Boolean,
      default: false,
    },
  },
  { timestamps: true }
);

Protected Routes

You can protect your other express API endpoints using authMiddleware. If the token sent in the request header is invalid or missing, a 403 Forbidden response is sent with a message of Invalid or expired token or No authorization credentials sent or Invalid token! or User not found if token is valid but no matching user.

const { authMiddleware, adminMiddleware } = require("node-mongoose-auth");

app.get("/powers", authMiddleware, (req, res)=>{
  // auth middleware attaches the current user to the request or returns a 403 Forbidden response
  const loggedInUser = req.user
  if(user.isAdmin){
    res.json("You are a superuser")
  }else{
    res.json("You are a regular user")
  }
});

/**
 * Admin routes. Note that the authMiddleware should always come
 * first.
*/
app.get("/powers", authMiddleware, adminMiddleware, (req, res)=>{
  // auth middleware attaches the current user to the request 
  // admin middleware checks for isAdmin permissions
  const loggedInUser = req.user
  if(user.isAdmin){
    res.json("You are a superuser")
  }else{
    res.json("You are a regular user")
  }
});

Working with the User model

const { User } = require("node-mongoose-auth");
const users = await User.find();

Code Examples

Login example using axios package.

const axios = require("axios");

const handleLogin = async() => {
  const endpoint = "/api/auth/login";

  const payload = {
    email: "randomuser@example.com",
    password:"somestrongpassword"
  }

  const axiosConfig = {
    headers:{
        "Content-Type": "application/json",
    }
  }

  const res = await axios.post(endpoint, JSON.stringify(payload), axiosConfig);
  const {token, user} = res.data;

  localStorage.setItem("token", token);
}


const handleRegister = async() => {
  const endpoint = "/api/auth/register";

  const payload = {
    firstName: "John",
    lastName: "Doe",
    sex: "Male",
    email: "randomuser@example.com",
    password: "somestrongpassword",
    address: "Kampala, Uganda", // Optional
    mobile: "256782000000", // Optional
    birthDate: "1987-03-12", // Optional
    about: "" // Optional
  }

  const axiosConfig = {
    headers:{
        "Content-Type": "application/json",
    }
  }

  const res = await axios.post(endpoint, JSON.stringify(payload), axiosConfig);
  const { token, user } = res.data;

  localStorage.setItem("token", token);
}


const getUser = async (token)=> {
  const endpoint = "/api/auth/getuser"
  const res = await axios.get(endpoint, {
    headers:{
      "Content-Type": "application/json",
      "Authorization": `Bearer ${token}`,
    }
  });

  return res.data
}

Creating superusers from the CLI

A command-line script has been added to ease the process of creating superusers.

npm run createsuperuser -- --mongo_uri="mongodb://localhost/mydb" --email="admin@company.com" --firstname="John" --lastname="Doe" --sex="Male" --password="password"

Run: npm run createsuperuser -- --help for details and available aliases.

Gotchas

  1. The way mongoose handles schema means that you can't easily customize the UserSchema or add middleware. If you must do so, make sure you import the UserSchema first and customize it before the call to mongoose.model().
const UserSchema = require("node-mongoose-auth/models/UserSchema");

// Customize the schema
UserSchema.pre("save", function(){
  console.log("Saving new user...")
})

const { authRouter } = require("node-mongoose-auth")

...

app.use("/api/auth", authRouter);
  1. You must use this middleware with json data only.
  2. The Authorization header Prefix must be "Bearer" otherwise it will throw Invalid token prefix error.
  3. Failure to set the SECRET_KEY environment variable with cause runtime errors.

Good Luck! Constructive criticism and ideas are welcome.