Add Basic Auth to Pa11y

Add Basic Auth to Pa11y

Official Pa11y logo
Official Pa11y logo

Pa11y is a great open sourced automated accessibility testing tool.
It uses headless Chrome browser and HTML_CodeSniffer as test runner.

Unfortunately out of the box Pa11y Dashboard doesn’t come with any form of authentication. This might be OK for some people, but in our case we’re going to add basic-auth to it.

This short tutorial is based on pa11y-dashboard v3.1.0.

Enter http-auth

I’ve selected http-auth package to do the job as it’s a popular and actively maintained package.
Since v4.0.0 (Feb 2020) the “Connect integration with http-auth module” (a.k.a. connect middleware) was moved to a separate module .
It means that we have to also include http-auth-connect in our project.


First things first. Pa11y Dashboard requires MongoDB to store task data & test results.
Spin it up with docker:

docker run -d --name pa11y-mongo -p 27017:27017 mongo:4.2.6

The next step is to add new dependencies to package.json:

--- a/package.json
+++ b/package.json
@@ -30,6 +30,9 @@
     "compression": "~1.7.4",
     "express-hbs": "~2.1.2",
     "express": "~4.17.1",
+    "http-auth": "^4.1.2",
+    "http-auth-connect": "^1.0.4",
     "http-headers": "~3.0.2",
     "moment": "~2.24.0",
     "pa11y-webservice-client-node": "~2.0.0",

The last steps in this section is to install project dependencies with:

npm install


Once we’re done with dependencies, we have to have a way to specify authentication credentials.
Let’s do that using environment variables. These can be easily defined in config.js:

--- a/config.js
+++ b/config.js
@@ -28,12 +28,19 @@ if (fs.existsSync(jsonPath)) {
       port: Number(env('PORT', '4000')),
       noindex: env('NOINDEX', 'true') === 'true',
       readonly: env('READONLY', 'false') === 'true',
+      username: env('USERNAME', null),
+      password: env('PASSWORD', null),

Changes, changes, changes…

Finally we have to inialize http-auth modules and plug them in to Pa11y app.

--- a/app.js
+++ b/app.js
@@ -23,12 +23,28 @@ const hbs = require('express-hbs');
 const http = require('http');
 const pkg = require('./package.json');

+// Import http-auth modules
+const auth = require('http-auth');
+const authConnect = require('http-auth-connect');
 module.exports = initApp;

 // Initialise the application
 function initApp(config, callback) {
        config = defaultConfig(config);

+    // Configure basic auth
+    const basic = auth.basic({
+            realm: "Visible user area"
+        }, (username, password, callback) => {
+            // Custom authentication
+            // Use callback(error) if you want to throw async error.
+            callback(username === config.username && password === config.password);
+        }
+    );
        let webserviceUrl = config.webservice;
        if (typeof webserviceUrl === 'object') {
                webserviceUrl = `http://${}:${webserviceUrl.port}/`;
@@ -54,6 +70,13 @@ function initApp(config, callback) {
                extended: true

+    // Add authentication module to Pa11y app.

Start the service

We’re now ready to roll!
Start the dashboard with:

PORT=8888 USERNAME=a PASSWORD=a node index.js

Pa11y Dashboard started
mode: undefined
uri:  http://:::8888
Server running at:

Pa11y Webservice started
mode:     undefined
database: mongodb://localhost/pa11y-webservice
cron:     0 30 0 * * *

Then visit enter your username and password and start using Pa11y 💪😁!