GitHub Repository

Routing Structure

Our app has a single home route inside our server.js file. That was great for testing purposes but unfortunately — for LOTR fans —, we will have to replace it with a better structure for our routing system.

We won’t need the Express router to handle any other routes than our API’s endpoints. For our frontend, we will need it to serve our initial index.html file and from there on we’ll let Angular take the lead.

Let’s jump right into it and replace the home / route with the following:

It requires our API’s routing function in which we pass the passport instance as a parameter. It then bundles all routes under /api, a very common API endpoint structure.

It creates a catch-all route that always responds with an index.html file. As you can see, we’re not using any view engine here as it’s out of the scope of this tutorial, but feel free and set-up Pug or any other Express compliant view engine.

Inside the /public/app/views folder create a new file called index.html.

# routes/api.js

This is the file where we will orchestrate our entire application’s routing. It’s not doing much yet other than initializing the router, requiring the config file and finally creating and exporting the APIRoutes function.

A small thing to note is that the APIRoutes function accepts the passport instance as a param — which we passed earlier.

The // TODO: comment looks boring as hell, don’t you think? Let’s replace it with something fun. I was thinking about the endpoint for creating a new account.

Registering Users

# routes/api.js

We use the Express router to register a new POST request to the /signup endpoint and pass as a second argument the AuthController.signUp method.

Finally, we return the router instance which is handled as middleware inside server.js when we’re nesting all routes under /api.

Now, when we’ll make a POST request to the http://localhost:8080/api/signup endpoint, the AuthController.signUp method should run. The problem is that we don’t have any AuthController object with a signUp method available yet.

When a POST request will be made to the request to the /api/signup endpoint, the AuthController.signUp method should run.

It won’t work for now as we haven’t created the AuthController yet. Let’s create a new file called authController.js inside our app/controllers folder and then require it in the api.js file.

That’s a lot to take in as a single bite. Let’s break it down and analyze it:

First, we check if the username and password are available on the request body and respond with a friendly message if that’s not the case letting the user know that both should be provided.

This is a great place to do in-depth checks. For example, you could ask the user for a second password and check if both are identical to avoid any typing errors and potential login issues afterward.

If everything is fine and all required data is provided, we sync the db and then attempt to create a new user. If the user is created successfully, we respond with a message, otherwise, we let the ‘user’ know that there was a problem during the attempt. In this case, we let the person know that the username already exists.

We can restart our server and test the new endpoint. As you can see below, I managed to create a new user using Postman and received the expected response.

Checking the database confirms the account was successfully created.

Excellent! We now have a working sign-up endpoint and people can create new accounts.

First, we check if the username and password are provided. If not, we let the ‘user’ know.

If both credentials are provided, we then try to find a single user where the username matches the one provided by the person attempting to log-in. If no user is found, we respond letting them know.

Having a user found in the database matching the request, we then proceed to comparePasswords using the model instance method we created in the previous article. If the passwords match, we then use the jsonwebtoken library to sign the token using the secret key stored in our config file, setting the username as a payload and setting the expiration time to 30 minutes.

Tip: It’s considered a best practice to store the token expiration time inside the config file.

If the passwords do not match, we let the ‘user’ know about the failed login attempt. We also attempt to catch any potential error if something else goes wrong.

We wrote a lot of code, let’s get back to Postman and make sure everything works as expected and we can login with the user account created earlier. If everything went well, your response should look similar to the screenshot below.

Perfect, we are now able to log in and use the token provided by the server.

Following we will continue to set up the user roles and create a new route for each user type. Crazy fun stuff!

User Roles

Currently, we have only one generic user type and no way of grouping users. It’s no fun having an application where anyone can access everything. We want to restrict access to specific routes based on user role so our annoying neighbor couldn’t create an account, log in and change our application’s settings in the future.

At the end of our config.js file, we need to define the user roles and the access levels for each user role. For our little app, we will create only three user types: Guests, (registered) users and admins.

We first define the three roles needed with values when converted to 32-bit integers, translate to the values added in the comments.

Then we define the access level for each area based on user role using the bitwise OR operator.

The guest area can be accessed by all three user types, guests, registered users and admins.

The user area can be accessed only by registered users and admins.

The admin area can be accessed only by admin users.

By doing this we added a clear distinction in how we want to group our routes based on access level and user role. We can also extend it in the future by adding new roles or access levels if the business requirements introduce new functionality.

This is great! We are now almost ready to create our first protected route for registered users or admins. Before that, we still have a few small steps to make which consists of modifying the User model and creating a helper function that checks the user role before running the controller’s callback hooked to our route.

Updating the User Model

Before anything else, we need to update our User schema to reflect the role changes in the model definition.

We set the role type as a Sequelize.INTEGER which is enough for our neeeds and set the defaultValue to a basic user role.

Make sure you drop the existing users table as we haven’t implemented migrations or written any code to alter the table as it’s out of the scope of this tutorial. Skipping this step will result in errors when creating new users.

We begin by exporting an allowOnly function that returns another function called checkUserRole.

The allowOnly function accepts an accessLevel and a callback function as params. Both will be provided by us while defining new routes that need to be protected. The callback function will represent the controller method that needs to be called when the route is accessed and the accessLevel the allowed user types to that route.

The returned function will act as a middleware function for our routes as it accepts both the request and response params.

Before calling our callback function we have four lines of code that define our route protection. We check if the request user role — which will be provided by the passport library — has access to this route based on the accessLevel we provided. If not, we respond with 403 - Forbidden. If the user has access, we then call our callback function and pass it the request and response.

We are now finally ready to create our first protected route.

User Protected Route

Inside the routes/api.js file, let’s add a protected route both using the passport library to check the user’s token and our new allowOnly function.

# app/routes/api.js

The code above create a new route called /profile and uses passport‘s authenticate() method to verify the user’s token. Finally, we use our allowOnly function in which we provide the user access level and the index method of a UserController.

This won’t work yet as we haven’t included the allowOnly function in our file or the non-existent UserController. Let’s do that first.

Inside our app/controllers folder, we create a new file called userController.js and inside we define the UserController and the index method.

Looks complete to me, except for not having an admin user yet. We can register a new one and change the user role in the database manually.

Logging in with the new admin user and attempting to access the /api/admin route should now work.

Excellent! Now we can test and make sure the regular users can’t access the admin only route using a regular user token.

As expected the server returns 403 - Forbidden.

Conclusion

Congrats! We managed to finish the remaining backend functionality and now have a working RESTful API that supports user registration, authentication and prevents route access based on user role. We are now ready to jump into building our application’s frontend using Angular.

Don’t be shy! Share your thoughts about this post or ask for help if you’re stuck in the comments below. I’ll be glad to assist.

Next Up:

Creating a Role-Based User Authentication System with Angular, Express and MySQL — Part 3: The Front-end

Sharing is Caring

If you 💖 this post, I’d appreciate if you’d let your friends know about it too. You can use the floating buttons to share this post on various social networks. Thanks! 🙂

SteppenWolf

Hi Catalin!

First of all, thanks a lot for this awesome tutorial! Its helping me a lot in a project that im working on before ending my grade. But im having a issue.
When setting up that routes are protected, when i send a get request without token in Postman, i get the expected result with an Unauthorized response. But, when i try, as in your example, to send a Authorization header with the signin user token, i still get an Unauthorized response (?). I checked all the the methods on api and auth controller. What could be the problem?

With these changes I been able to get my response 'Welcome to user area (email) ' correctly.

Anyways, thanks for your quick response. There any advice that you could give when scalating the project?

Thanks again

Rama Astadipati

Wow thank you so much for writing the very comprehensive tutorials, I think you need to make project on Udemy or other some place then posting here, then i’ll be your students as well.
Thank you so much @hiskie:disqus

Hey. Is it also possible to do with with another framework such as jquery

Nathan

jQuery is for manipulating the DOM on the front end. All of the code thus far has been back end Node.js.

Mhuka Huru

Sorry. My question was a bit vague. How easy is it to integrate that with a front end framework other than AngularJS

ronnel matallana

hi catalin,if i want to catch info by a auth token and store in a var, and use it in a sequelize bd query in a get controller how is supposed to do it?

Rani Somu

Thanks for the article. It’s really very helpful.
Could you guide me to do one more api (to fetch data from another table like mark) for authenticated user.
Thanks in advance

Chisom Igwe

hey, Your tutorial has been amazing and so helpful . I keep on getting an Error:[$compile:tpload] error eventhough i used nearly the exact same code as you and this means that none of my partials are showing up. I have trued every solution in stackoverflow but none work. Any advice?