So we have seen how we created Current User utility, which is a powerful one, but that one was only with the Guest user. Now we will see how we can create a Current User utility with the Logged In user.
How this works
So let's see how this works first, we'll first check if the user is passing his/her credentials, if yes, then we'll check if the credentials are correct or not, if yes, then we'll create a JWT token and we'll pass the user payload to JWT when generating the token, this will be used to identify the user when he/she will make a request to the server again with the JWT token.
Login Controller
Our login controller now looks like:
// src/app/users/controllers/login.ts
import User from "app/users/models/user";
import { Request } from "core/http/request";
import { Response } from "core/http/response";
export default async function login(request: Request, response: Response) {
// get the email and password from the request body
const { email, password } = request.only(["email", "password"]);
const user = await User.attempt({ email, password });
if (!user) {
return response.badRequest({
error: "Invalid credentials",
});
}
console.log("Logged in successfully");
// generate access token
return response.success({
user: user.data,
});
}
As you can see, there is a comment in the controller generate access token, but sadly there is no generated token 🥺, so let's generate the token.
We already have our own jwt which can generate a new token, that's what we'll do right now.
Generate Access Token
So let's create a new method in the User model, which will generate a new token for the user.
// src/app/users/controllers/login.ts
import User from "app/users/models/user";
import jwt from "core/auth/jwt";
import { Request } from "core/http/request";
import { Response } from "core/http/response";
export default async function login(request: Request, response: Response) {
// get the email and password from the request body
const { email, password } = request.only(["email", "password"]);
const user = await User.attempt({ email, password });
if (!user) {
return response.badRequest({
error: "Invalid credentials",
});
}
// generate access token
const token = await jwt.generate({
...user.only(["id", "_id"]),
userType: "user",
});
return response.success({
user: user.data,
// send the access token to the client
accessToken: token,
// send the user type to the client
userType: "user",
});
}
Here we generated a new token using jwt.generate method, and we passed the user payload to the jwt.generate method, so that we can identify the user when he/she will make a request to the server again with the JWT token.
Now let's give it a try, and see if it works or not.
Don't forget that the
/loginrequires a Bearer Token, which will be in this case theGuestaccess token.
Now open Postman and make a POST request to the /login route, and pass the email and password in the request body.
Don't forget to pass the
Authorizationheader with theBearertoken.
You should see something like this:
From now on, we can use this access token to make requests to the server, now let's see if it works.
Logged In User With list users
Now let's update the list users request to make it only accessible to the logged in user only.
We already have authMiddleware added in the /users request, but we need to tell it allow only the user user type, so let's modify that middleware to receive a userType parameter, and we'll use that parameter to check if the user is of the same type or not.
If no arguments passed, it will be accessible to all the user types.
// src/core/auth/auth-middleware.ts
import config from "@mongez/config";
import { Request } from "core/http/request";
import { Response } from "core/http/response";
import { setCurrentUser } from "./current-user";
import jwt from "./jwt";
export async function authMiddleware(request: Request, response: Response) {
try {
// use our own jwt verify to verify the token
await jwt.verify();
// get current user
const user: any = request.baseRequest.user;
// now, we need to get an instance of user using its corresponding model
const userType = user.userType;
// get user model class
const UserModel = config.get(`auth.userType.${userType}`);
// get user model instance
const currentUser = await UserModel.findBy("_id", user._id);
// set current user
setCurrentUser(currentUser);
} catch (err) {
// unset current user
setCurrentUser(undefined);
return response.badRequest({
error: "Unauthorized: Invalid Access Token",
});
}
}
This is the current state of the middleware file, what're going to do now is what we call Higher Order Function
Higher Order Function
A higher-order function is a function that does at least one of the following:
- Take one or more functions as an input
- Output/Return a function
It can be one of these cases or both.
In our case, we're going to create a function that takes a userType parameter, and returns a function that will be used as a middleware.
// src/core/auth/auth-middleware.ts
import config from "@mongez/config";
import { Request } from "core/http/request";
import { Response } from "core/http/response";
import { setCurrentUser } from "./current-user";
import jwt from "./jwt";
export function authMiddleware(allowedUserType?: string) {
return async function auth(request: Request, response: Response) {
try {
// use our own jwt verify to verify the token
await jwt.verify();
// get current user
const user: any = request.baseRequest.user;
// now, we need to get an instance of user using its corresponding model
const userType = user.userType;
// check if the user type is allowed
if (allowedUserType && userType !== allowedUserType) {
return response.unauthorized({
error: "You are not allowed to access this resource",
});
}
// get user model class
const UserModel = config.get(`auth.userType.${userType}`);
// get user model instance
const currentUser = await UserModel.findBy("_id", user._id);
// set current user
setCurrentUser(currentUser);
} catch (err) {
// unset current user
setCurrentUser(undefined);
return response.unauthorized({
error: "Unauthorized: Invalid Access Token",
});
}
};
}
Here we moved the auth middleware function into the function and called it auth, this is a kind of nested functions, a function inside a function and we also returned it. the authMiddleware function now can receive a userType parameter, and it will return a function that will be used as a middleware.
Then we checked if the allowedUserType is passed, and if it's passed, we checked if the user type is the same as the allowedUserType, if not, we'll return an unauthorized response.
Now let's update the /users route to use the authMiddleware with the user user type.
// src/app/users/routes.ts
import { authMiddleware } from "core/auth/auth-middleware";
import router from "core/router";
import login from "./controllers/auth/login";
import createUser from "./controllers/create-user";
import getUser from "./controllers/get-user";
import usersList from "./controllers/users-list";
router.get("/users", usersList, {
middleware: [authMiddleware("user")],
});
router.get("/users/:id", getUser);
router.post("/users", createUser);
router.post("/login", login);
Now let's try to make a request to the /users route, and see if it works or not.
Try first with no Authorization header, you should see a unauthorized response.
Then try it with guest access token, you should see an unauthorized response.
Now try it with user access token that we got from /login request, you should see a list of users.
Current User as Logged In User
Now we can use the user function to get the current user, and we can use it in the usersList controller.
// src/app/users/controllers/users-list.ts
import { user } from "core/auth/current-user";
import database from "core/database";
import { Request } from "core/http/request";
export default async function usersList(request: Request) {
const usersCollection = database.collection("users");
// log the current user
const users = await usersCollection.find({}).toArray();
console.log(user());
return {
users,
};
}
You should see the logged in user in the console, you should see the logged in user in the console.
🎨 Conclusion
In this article, we learned how to generate a JWT for logged in user, and also how to make a middleware to protect routes based on user type.
☕♨️ Buy me a Coffee ♨️☕
If you enjoy my articles and see it useful to you, you may buy me a coffee, it will help me to keep going and keep creating more content.
🚀 Project Repository
You can find the latest updates of this project on Github
😍 Join our community
Join our community on Discord to get help and support (Node Js 2023 Channel).
🎞️ Video Course (Arabic Voice)
If you want to learn this course in video format, you can find it on Youtube, the course is in Arabic language.
📚 Bonus Content 📚
You may have a look at these articles, it will definitely boost your knowledge and productivity.
General Topics
- Event Driven Architecture: A Practical Guide in Javascript
- Best Practices For Case Styles: Camel, Pascal, Snake, and Kebab Case In Node And Javascript
- After 6 years of practicing MongoDB, Here are my thoughts on MongoDB vs MySQL
Packages & Libraries
- Collections: Your ultimate Javascript Arrays Manager
- Supportive Is: an elegant utility to check types of values in JavaScript
- Localization: An agnostic i18n package to manage localization in your project
React Js Packages
Courses (Articles)


Top comments (0)