Secure Your Sitecore Next.js Site Using Middleware

Example Subheading

November 28, 2022

By David Austin

Let's say you have a Sitecore JSS site running Next.js and you want to secure either a portion or all of it. This might be because you have a QA environment you want to secure, or you want to lock down a portion for other purposes. While there are a number of options, using middleware is friendly to the end-user as well as to the author who might be using Experience Editor.

Update Your Next.js Version

One thing to keep in mind is when you might have started your Next.js project, it was < 12.3. While you can make it work, this approach will not work properly as prior to 12.3, middleware was in beta.

Create The Middleware File

If you're using Docker, you likely have a folder structure that resembled ../rendering/companyABC/src. You need to create a file called middleware.ts in this folder. As of 12.3, partial middleware - commonly delineated by a file called _middleware.ts and found under pages/ folder, is no longer supported.

Setup

Let's create a simple middleware.ts file.

import { NextRequest, NextResponse } from 'next/server';
export function middleware(request: NextRequest) {
    return NextResponse.next();
}

It's important to note that the above setup, while simple, will actually break your Experience Editor. One way to get around this is to have two rendering hosts, one with middleware and one without. Not everyone has this ability, so instead, Next.js has an alternative.

Configuring A Conditional Middleware

Thankfully there is a way to run the middleware on specific routes, e.g. /about or say secret. What if you need to secure it on everything but a specific route? This will ensure POST calls from within Experience Editor don't run the middleware and break.

export const config = {
    matcher: ['/((?!api|sitecore|-|_next|static|favicon.ico).*)', '/'],
};
  

We prevent it from running on our API calls, the /sitecore folder and the /-/media folder.

You may have requirements for additional routes to remain unblocked, but we found these were the minimum to have Experience Editor remain operational while having a secure front end.

Complete Setup

We've added an example below where you'd check to see if a person is authorized. This could be basic authentication or IP restriction. We then also check for the __prerender_bypass cookie which is only present when in Experience Editor. Otherwise, what ends up happening is some of the calls that shouldn't be re-written break any chance of authoring using Experience Editor.

import { NextRequest, NextResponse } from 'next/server';

function isAuthorized() {
    ...
}

export function middleware(request: NextRequest) {
    const hasPrerenderBypass =
    request.cookies.get('__prerender_bypass') != null &&
    request.cookies.get('__prerender_bypass') != '';
    if (!isAuthorized() && !hasPrerenderBypass){
        const loginUrl = new URL('https://companyabc.com/403', request.url);
        errorPage.searchParams.set('from', request.nextUrl.pathname);
    }
    return NextResponse.next();
    
}
export const config = {
    matcher: ['/((?!api|sitecore|-|_next|static|favicon.ico).*)', '/'],
};

And that's it. Hope this helps you out.

Image of Fishtank employee David Austin

David Austin

Development Team Lead | Sitecore Technology MVP x 3

David is a decorated Development Team Lead with Sitecore Technology MVP and Coveo MVP awards, as well as Sitecore CDP & Personalize Certified. He's worked in IT for 25 years; everything ranging from Developer to Business Analyst to Group Lead helping manage everything from Intranet and Internet sites to facility management and application support. David is a dedicated family man who loves to spend time with his girls. He's also an avid photographer and loves to explore new places.