Protect your API routes in Next.js with Middleware
Photo by James Sutton / Unsplash
Next.js 12 had significant features and improvements like the build times 5x faster; another exciting feature released called Edge Network allows you to deploy your functions in the Edge and increase the execution speed.
An extension of this feature is the support of middleware in a Next.js application. A middleware is a function that sits in front of your application routes. It is executed before the request reaches the business logic associated with a route.
With middleware, you can do many things like:
- Geolocate a user based on IP address
- Implement API rate limiting
- Detects the user language and redirects to the appropriate page.
- Restrict access to specific routes
On this page, you can find other use cases for Edge functions on Vercel
In this post, we will see how to protect our API routes using the middleware.
The use case
The picture below shows the available API routes on a Next.js application with the restriction we want to apply:
With a library like Next Auth, you can handle this case, but one of the concerns is that you will have to add the authorization check on each route. With the middleware, you will do it in one place, and it works for all the routes.
We will not implement the token generation and will pass the plain user role to the request header "Authorization".
Setup the project
We will use the Next.js starter project to create a project with typescript. Make sure to install a version of Next.js >= 12.
Run the commands below to install the project and start the application:
npx create-next-app@latest --ts next-api-middleware
cd next-api-middleware
yarn dev
Navigate to http://localhost:3000 to make sure the application works as expected.
Now we will create our API routes:
- /api/login.ts
- /api/contact.ts
- /api/users/create.ts
- /api/users/list.ts
- /api/admin/list.ts
Finally, the file that contains the list of users in /data/users.ts
The folder structure now looks like this:
Run yarn dev
to start the application, if we test the application using an HTTP client, we realize we can access all the routes.
Let's use the middleware to protect the routes.
Protect API routes
The middleware is executed before hitting the route's logic. The project can only file in the root directory. Inside this file, we must write do two things:
- Define the routes where this middleware will apply. As you can guess, all the routes under /api/users and /api/admin.
- Define an action to execute before continuing the request execution.
The middleware filename must be called, middleware
followed by the extension.
Create the file middleware.ts
and add the code below:
The middleware just forwards the request to the route, but the interesting part is the config
variable.
The properties matcher
is an array of routes to apply the middleware on. It supports the wildcard syntax so you can match a group of routes.
The syntax /api/users/:path*
says: Apply the middleware on all the routes that starts with /api/users
. It will match the routes like /api/users/123
, /api/users/profile
, etc...
Note: The matcher
values need to be constants so they can be statically analyzed at build-time. Dynamic values such as variables will be ignored.
Restrict the user's routes
Update the file middleware.ts
with the code below:
We retrieve the authorization value from the request header, and if it doesn't match, we redirect the user to the unauthorized route that will return a 401 status code.
If the value match, we forward the request to the next middleware if there is one or to the route directly if there is no middleware.
Restrict the admin routes
Update the file middleware.ts
with the code below:
The code of the API route /api/auth/unauthorized
is straightforward:
Now, start the application yarn dev
and test again:
Test the API endpoints with Postman
Now our endpoints are protected ?
Beware of your middleware size
At the moment I'm writing this, the middleware size is limited to 1MB. When building the production application, you will get an error if the build size exceeds.
Wrap up
We can summarize that the middleware provides a great way to handle actions that applies to a group of routes. It can also be used on the frontend side.
Learn more about Next.js middleware here: https://nextjs.org/docs/advanced-features/middleware
You can find the code source on the GitHub repository.
Follow me on Twitter or subscribe to my newsletter to avoid missing the upcoming posts and the tips and tricks I occasionally share.
Happy to see you soon ?