DEV Community

Penn
Penn

Posted on • Updated on

NextJS Authentication over Nginx

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

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' })
  }
}
Enter fullscreen mode Exit fullscreen mode

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;
  }

}
Enter fullscreen mode Exit fullscreen mode

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

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

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

location /  {
    auth_request     /auth;
    auth_request_set $auth_status $upstream_status;
    error_page 401  /signin?redirect=$request_uri;
    proxy_pass              http://localhost:3030;
  }
Enter fullscreen mode Exit fullscreen mode

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

Data Fetching: getServerSideProps | Next.js

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.

Top comments (0)