Techtales.

Handling Authentication with JWT in NextJs
TD
The Don✨Author
Jul 28, 2024
6 min read

Handling Authentication with JWT in NextJs

43

Authentication is crucial in every app, and ensuring sufficient security is vital whether you are creating a small app or a production ready deployment. Understanding auth concepts such as hashing, cryptography and so on could be challenging, but luckily there are few libraries that simplify the process.

For this blog, I will explain how I have implemented authentication in my app using json web token and server actions in NextJs. Since NextJS is a fullstack app, the concept of CORS will not be covered here. 

To begin we need to install the relevant libraries. This include jsonwebtoken, jose, and bcrypt.js. There are vital to encoded and decode user password stored in the database. I am using a postgress database with PRISMA orm.

To get started, assuming you have all the necessary setup (NextJS app and database), run the following command:

Jose is similar to jsonwebtoken but also works in browser environment, enabling you to decode the token if you need the data in the frontend.

Next, we are going to create a JWT_SECRET that will be used to hash the passwords. You can set this to any random number or use openssl to generate the token by running the command:

Save the token in .env file, without the .local prefix to ensure it is not exposed into the browser environment. 

NOTE: It’s crucial that you keep this key private and only accessible to the server. You can use a dot env provider or keep it in a secure location. Be sure you set it in Next.js without the NEXT_PUBLIC prefix.

If you accidentally leak the key to the client, then an attacker could use your key to sign bogus credentials with whatever role they like and gain full access to your platform!

Next we are going to tap into the power of middleware in NextJs. Middleware is the cornerstone of our authentication system, designed to protect routes that require authentication.

By implementing this, you ensure that only authenticated users can access certain parts of your application, safeguarding sensitive information and user privacy.

NextJS already includes a middleware.js file but if it does not exist, create one in the root directory and name it middleware.js. Add the following code to the middleware.

Note we are using jose instead of jwt since we need to read user data rather than just check if the token exists. If we just check if the token exists, a user can create a token with nothing and be authenticated.

The matcher object configures the path that you want the API to match. You can modify the protected and public routes, and make sure to include them in the matcher function.

Next we are going to create a login functionality that utilizes PRISMA to find and authenticate the user and return a http only cookie in the response body. It is better to create this in an api route.

Here is the login function in a file called /api/auth/login:

You can add some more complicated functionalities, such as checking the request ip address to rate limit the user. If you wish to add a rate limiter in the login function, you can get user ip address by doing the following:

I know this is alot of if requests, I am guilty but you can also streamline this code to make it more efficient. In the register route, you can use the same functionality in the login route to return the http code. 

Now we need to create a helper function that you can call to get the user. Remember this function cannot return the user in the frontend, it will only work in the server.

This function enables you to decode the token but does not account for scenarios where the token exists but is expired and you might need to further modify it to handle such scenarios. 

To get user data, create a route (/api/me) where you can fetch the user data each time there is a logged in user. This route will receive the request cookies and use decodeToken function to return user data:

With the current setting, you can fetch user data and save it in context each time the user logs in. This ensures that components that need user data have access to the data.

Creating Logout Route

Creating a logout route is as easy as just deleting the token. Create a new route in /api/auth/logout and add this code:

Conclusion

We’ve covered the use of JWTs for efficient user authentication, storing user data in cookies for quick access, and the importance of custom middleware for route protection. 

Remember, the journey to secure and efficient authentication is ongoing and ever-evolving. The strategies and tools we’ve discussed are at the forefront of current best practices, providing a strong foundation for your Next.js applications.

However, the world of web security is dynamic, so staying updated with the latest trends and updates is crucial. Adding the rate limiter is also necessary to protect the login route from brute attack.

 

4
3