Protect Custom Routes in Docusaurus using AWS Cognito
A guide on how to protect specific paths in your Docusaurus website utilizing AWS Cognito
Background
In my previous article, we already figured out how to add an authentication layer to a Docusaurus website and secure the whole website using AWS Cognito.
Though, what if you want to:
- Secure one of your specific routes like
/docs/*
or/admin/*
to provide enterprise documentation for your customers?
OR
- Create an internal documentation website to provide in-depth details for your products only for your internal team.
Goal
The main outcome of this guide is to provide a step-by-step guide on how you can protect a specific route like /docs/*
in your Docusaurus website using AWS Cognito.
Please find the more advanced authentication flows using Docusaurus and AWS Cognito here.
Getting Started
Before we dive into the tutorial, let's assume you've already set up a simple authentication layer as explained in my previous article. This guide is the next step after that.
Prerequisite
An AWS account
A running Docusaurus website with a simple authentication layer is described here
Docusaurus Setup
This section contains all the changes and new files needed to be added to the Docusaurus website.
Final Directory Hierarchy
Here is the final directory tree which mostly shows the changes added/modified to the base project. Use it as a reference.
└── src
└── utils
└── constants.js
Adding Required Files
In this section, I will provide the changes or additional files required for this feature to work.
🔔 On the first line of each code block, you can find the relative path of the file.
constants.js: This file contains the most important constant values giving easier management of the project.
In this file, we have a constant value named
PROTECTED_PATHS
that contains the list of the routes or paths that need to be protected.As of now, the
BASE
URL is protected which means the whole website is protected and you need to authenticate when you open the website.Though we don't want to protect the whole website. We want to ask the user to authenticate only if he wants to access the
/docs/*
route and any other route under this route for example/docs/intro
.The reason we use this constant value is hidden in the
Auth
component that is described below.The logic is:
If the requested route is one of the values in the list of routes we have in
PROTECTED_PATHS
(line 39), then it will redirect to the/login
page (line 40); Otherwise, will redirect to the requested page which means the path is not protected.When it is redirected to the
/login
page:If the user is authenticated (line 30), it will redirect to the requested page (line 36).
If the user is not authenticated (line 30), it will show the
/login
page (line 41).// src/components/Auth/index.js import React from "react"; import { useAuthenticator } from "@aws-amplify/ui-react"; import { Redirect, useLocation } from "@docusaurus/router"; import { AUTHENTICATED, BASE, LOGIN_PATH, LOGOUT_PATH, PROTECTED_PATHS } from "../../utils/constants"; import { Login } from "../Login"; export function AuthCheck({ children }) { const location = useLocation(); let from = location.pathname; const { route, signOut } = useAuthenticator((context) => [context.route, context.signOut]); // If it is not authenticated and tries to access the protected paths. Also, a // custom error appears if anything happens. if (route === AUTHENTICATED) { if (from === LOGOUT_PATH) { signOut(); return <Redirect to={BASE} from={LOGOUT_PATH} />; } else if (from === LOGIN_PATH) return <Redirect to={BASE} from={from} />; return children; } else { if (from === LOGOUT_PATH) return <Redirect to={BASE} from={from} />; else if (PROTECTED_PATHS.filter(x => from.includes(x)).length) return <Login />; else if (from === LOGIN_PATH) return <Login />; return children; } }
So, to utilize the above logic:
Remove
BASE
fromPROTECTED_PATHS
.Add
/docs
toPROTECTED_PATHS
.// src/utils/constants.js export const LOGIN_PATH = "/login"; export const LOGOUT_PATH = "/logout"; export const AUTHENTICATED = "authenticated"; export const BASE = "/"; export const LOGOUT_BUTTON = "Logout"; export const LOGIN_BUTTON = "Login"; // Add the protected paths here export const PROTECTED_PATHS = ["/docs"];
Source Code
You may find the full source code of this project here.
🔔 The code repository shared above consists of a few branches that all are related to the Docusaurus Authentication using AWS Cognito. Though, you can find the changes for this article in the branch called
feat-specific-route-protection
.
❗️DO NOT upload any
.env
to your public repository.To run the project on your machine, you only need to fill up the
.env.local
file as described WITH YOUR VALUES.To use your
.env
values in production, you need to add them to your hosting.Below I listed a few hosting options and how you can upload your
.env
variables as well.
Complete Docusaurus Authentication Series
Please find the complete roadmap here.
In this series, I will provide a step-by-step guide on how to add an authentication layer to your Docusaurus website using well-known auth providers like AWS Cognito, Google Firebase, Auth0, etc.
Also, you can find more advanced auth flows for complicated scenarios as well.
Support
In the end, if you find the articles useful, don’t forget to support me at least with a message :)