Heroku banner from linkedin

Ultimate Guide: How to Add Password Protection to Your NextJS Application Hosted in Heroku | Password Protection for NextJS on Heroku

Imagine you have an app that’s in a staging cycle, and you need to implement password protection for your NextJS application on Heroku, so that only people with a username and password could access the site.

As of now, Heroku doesn’t have an inbuilt setup to add password protection to your App. It is because this is something that the developer should do in the application layer.

So in this tutorial, we’ll explore the process of securing your NextJS App hosted on Heroku with a username/password and storage session so that you don’t have to retype the credentials over and over again.

My App structure looks something like this:

APPNAME

   /components

   /pages

   /public

   /scss

   /static

   /uploads

….

routes.js

server.js

cms.js

package.js

.env

You might have a different structure, but as you read through this blog, you will get the idea of how to add password protection to your NextJS app on Heroku.

As a first step, go to the file where you load your pages. In my case, it’s the pages/index.js file. Here is where the page is rendered. The idea is to prompt for a username and password before rendering the page.

My website is a headless CMS with its WordPress backend hosted on WPEngine and frontend on Heroku. So, today’s focus is entirely on the front end.

In that file, add a state hook to check if the user is logged in or not. Initialize the state hook inside the Page component:

import React, { useState } from 'react';

…

…

const Page = (props) => {

 const [isLoggedIn, setIsLoggedIn] = useState(false);

  …

After this, let’s create a function that will pop up a prompt asking for credentials like username and password. We will call this function in a moment:

const promptLogin = () => {
    const enteredUsername = prompt('Enter your username:');
    const enteredPassword = prompt('Enter your password:');

    if (enteredUsername === process.env.NEXT_PUBLIC_USERNAME && enteredPassword === process.env.NEXT_PUBLIC_PASSWORD) {
      localStorage.setItem('username', enteredUsername);
      localStorage.setItem('password', enteredPassword);
      setIsLoggedIn(true);
    } else {
      alert('Invalid username or password. Please try again.');
      promptLogin();
    }
  };

In the above function, we store the input from the username and password prompts in two respective constants. Then, we perform a conditional operation to check if the username is equal to NEXT_PUBLIC_USERNAME (I’ll show you how to add this environment variable shortly) and the same with the password.

To avoid prompts popping up every single time we refresh the page, we can introduce local storage to store the username and password if they’ve already been inputted previously. That way, you don’t have to type in your credentials after every refresh.

So, we set the username item to the ‘enteredUsername’ constant and the password to ‘enteredPassword’. If the condition passes, we change the state of isLoggedIn to true by calling setIsLoggedIn(true). Otherwise, an alert with the message “Invalid username or password. Please try again.” pops up, followed by calling the same function.

To add two environment variables to your app, go to settings:

Under “Config Vars”, click “Reveal Config Vars”.

Add NEXT_PUBLIC_USERNAME and set a value for it. Same for password NEXT_PUBLIC_PASSWORD.

The next step is to add the useEffect() hook.

After the line where you initialized the state, add the useEffect hook(don’t forget to import useEffect from ‘react’) like this:

import React, { useState, useEffect } from 'react';
…
…
…
…
 useEffect(() => {
    if (process.env.NODE_ENV === 'production') {
      setIsLoggedIn(true);
    } else {
      // If not in production, check credentials
      checkCredentials();
    }
  }, []);

As you can see, I added an extra logic to check if my current environment is production or not. If not, then I would want to prompt username and password. I created another function called checkCredentials that we will check if we have any local storage items for username and password.

 const checkCredentials = () => {
    const storedUsername = localStorage.getItem('username');
    const storedPassword = localStorage.getItem('password');

    if (storedUsername === process.env.NEXT_PUBLIC_USERNAME && storedPassword === process.env.NEXT_PUBLIC_PASSWORD) {
      setIsLoggedIn(true);
    } else {
      promptLogin();
    }
  };

This is the function that will be called initially when the page is loaded. If it cannot find any local storage items, it will prompt you for a username and password.

The Final step:

Just before the section where you return the JSX markup, add this line of code:

if (!isLoggedIn) {
    return null; // Don't render anything until user is logged in
  }

By this, the page won’t be rendered until it passes the credential check.

Leave a Reply

Your email address will not be published. Required fields are marked *