NextJS Authentication over Nginx
Tags: nextjs, auth, nginx
Published: 2023-04-27 07:23:24

NextJS doens’t provided internal authencation support such as private root, redirection for unauthenticated request.

This article introduce a approuch to use Nginx to help fill the gaps. 

# Steps

## Add an API to authenticate incoming request

`/next-app/pages/api/auth.tsx`

```tsx
import { NextApiRequest, NextApiResponse } from 'next'
import isValid from 'token/isValid'

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
 
  const token = req.cookies['access_token']
  // isValid is an function that check if the token is valid or not
  if (await isValid(token)) {
		res.status(200).json({ message: 'Hello from Next App!' })
  } else {
    res.status(401).json({ message: 'unauthorized' })
  }
}
```

PS: Please use the real isValid function for your project. 🙂 

## Protect private routes, redirect to signin page if unauthencated

Let’s say the Next App is serving on port `3030`. Nginx listens incoming request on `3000` and make redirection per configuration.

`nginx.conf`

```
server {
  listen 3000;
  listen  [::]:3000;
  server_name localhost;
  large_client_header_buffers 4 12k;
  gzip  on;
  gzip_types application/javascript application/json text/css;

  # Place this before the next one in order to take the high porior.
  location ~* ^/_next/data {
    auth_request     /auth;
    auth_request_set $auth_status $upstream_status;
    error_page 401 =401 /401;
    proxy_pass              http://localhost:3030;
  }

  location ~* \.(gif|jpg|jpeg|svg|png|ico|woff|woff2|js|css|json|yaml)$ {
    expires 1y;
    add_header Cache-Control "public";
    proxy_pass              http://localhost:3030;
  }

  location /_next/static {
    expires 1y;
    add_header Cache-Control "public";
    proxy_pass              http://localhost:3030;
  }

  # public routes
  location ~* ^/(sign_in|other-public-routes)/?$ {
    proxy_pass              http://localhost:3030;
  }

  location /  {
    auth_request     /auth;
    auth_request_set $auth_status $upstream_status;
    error_page 401  =3=2 $schema$host/sign_in?redirect=$request_uri;
    proxy_pass              http://localhost:3030;
  }

  location = /auth {
    internal;
    proxy_pass              http://localhost:3030/api/auth;
    proxy_pass_request_body off;
    proxy_set_header        Content-Length "";
    proxy_set_header        X-Original-URI $request_uri;
  }

}
```
Note: Make sure the `location ~* ^/_next/data` take a high prior by placing it before the static asset location `location ~* \.(gif|jpg|jpeg|svg|png|ico|woff|woff2|js|css|json|yaml)$` .

The incoming request will be redirected to `/auth` (actually `/api/auth` on Next App). When the response code is 401, a `[302](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302)` redirection to /signin will be returned to the client.  Then the user has to finish the `signin` process before actually visiting the protected pages/apis.

The sequence diagram would be:

![sequence diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ad1hcpxm2hbsmiksc2si.png)



Tips: use the online test to verify matched location with request uri.

[](https://nginx.viraptor.info/)

## Alternative when `$schema` or `$host` is transformed

Sometimes the $schema (either HTTPS or HTTP) or $host (e.g. www.notion.com) is not the same with the one that the user types in the address bar in the browser since the request was proxies by another gateway so the original host was replaced. In this case, using server-side redirect could resolve the problem.

`nginx.conf`

```tsx
location /  {
    auth_request     /auth;
    auth_request_set $auth_status $upstream_status;
    error_page 401  /signin?redirect=$request_uri;
    proxy_pass              http://localhost:3030;
  }
```

Since it’s server-side redirection, the redirect param has to be handled on the server side as well. 

[Data Fetching: getServerSideProps | Next.js](https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props)

# Summary

1. Add authencation API in NextJS app.
2. Perform redirection with Nginx

Nginx plays the key role in the sample. And you may get it that the authencation API could be replaced by any third part API.  And the flexibility is provided by Nginx.