✨ Announcing Render's $50M Series B. ✨

Password ProtectStatic Sites with PageCrypt

By Chris Castle

Render takes your infrastructure problems away and gives you a battle-tested, powerful, and cost-effective cloud with an outstanding developer experience. Focus on building your apps, shipping fast, and delighting your customers, and leave your cloud infrastructure to us.

Password protecting static sites is tricky. You could use window.prompt() to ask a site visitor to enter a password before the site content is revealed, but a resourceful visitor will quickly get around this with right-click, view source (or curl or numerous other ways). All of the site’s HTML, CSS, and JavaScript are served to the web browser, and they constitute the entirety of the site.

If you are using a backend API that the static site pulls data from (like many single-page apps do these days), you could require authentication for API requests, but this doesn’t protect the HTML, CSS, and JavaScript.

In trying to find a good solution for this for Render users, we discovered PageCrypt. It’s a free, open source library that allows you to password protect these static assets securely. Let’s investigate how PageCrypt works and test it out!

What’s it good for?

  • Protecting a static site
  • Cases where you don’t need (or can’t run) backend code

What are the drawbacks?

  • Only encrypts a single HTML file by default
  • Only supports a single shared password (no per-user passwords)

What is it, and how does it work?

PageCrypt is a novel solution to password protecting HTML without a backend. It’s a library you can use as part of your site’s build step or as a command line tool. It uses the Web Crypto API — currently supported by all major browsers — and a password to encrypt an HTML page, which you can then host on any static hosting platform, including Render! An HTML page encrypted with PageCrypt prompts the viewer for a password. Upon entering the correct password, the page is decrypted and its content replaces the password prompt.

Example static site password protected with PageCrypt

One potential concern with PageCrypt is that it only encrypts an HTML file by default. If you want to encrypt your CSS and JavaScript files, you’ll have to inline them in the HTML file. The same applies to images and any other binary assets; you’ll have to inline them as Data URIs. As with any authentication and authorization solution, you’ll want to determine what’s acceptable for your security requirements. Maybe you’re comfortable with the risk of images leaking but have higher security requirements for your JavaScript. In that case, the HTML page can link to the image files but should contain all your JavaScript. You can use many static site build tools to automate inlining assets in HTML. Webpack, Gulp, or Grunt are just a few that might be useful.

PageCrypt also doesn’t allow users to have individual usernames and passwords. It only works with a single, shared password. If you need the more fine-grained control provided by user accounts, check out a service like Auth0.

Try it out

Adding PageCrypt to the build step of a Hello World static site was straightforward. The instructions in the project’s README provide clear guidance on how to use PageCrypt as a library with browser-executed JavaScript, Node.js, or Deno, and how to use it as a CLI tool. I used the CLI in the build step of my example static site.

Add PageCrypt to your project as a dependency:

yarn add pagecrypt

Then update the build step in package.json to use the CLI:

  "scripts": {
    "build": "pagecrypt src/index.html dist/index.html $PASSWORD && cp -R src/css dist/"

The password is set using the $PASSWORD environment variable since we don’t want to store that in the code. Using an environment variable also allows you to change the password and rebuild the site quickly.

Here’s an example deployment of the site. The password is s3cr3t.

To get a deeper understanding of how PageCrypt works, try entering an incorrect password. Then right-click and view the source of the page. PageCrypt generated the contents of this page during the build step. Your original page content is encrypted inside a hidden <pre> element at the bottom of the HTML document.

A screenshot of a PageCrypt-encrypted HTML page in Google Chrome's elements inspector.
Encrypted HTML page inside the <pre> element.

After the correct password is entered, your page content is decrypted and shown.

To make it easier for users to access password protected pages, PageCrypt also allows you to create a “magic link” that decrypts the page without prompting the user for a password. The format for the magic link is https://<link-to-your-page>#<password>, placing the password in a URI fragment. Check out the project’s README section about magic links to better understand the security implications. When your browser goes to a URL containing a URI fragment, the fragment isn’t sent across the internet, but it does remain in the browser’s history.


It would be interesting to extend PageCrypt to do a number of things:

  • Automate the inlining of CSS, JavaScript, and image files
  • Encrypt multiple HTML files
  • Encrypt multiple files, including CSS, JavaScript, and image files

If you do end up extending it in your build process, let me know!


This version of PageCrypt is a rewrite of an older version of PageCrypt. That older version also inspired a few spin-offs that you might find useful:

Now try it out yourself! You can deploy the code to Render for free. The README provides step-by-step instructions.

Chris Castle

At the time of writing, Chris Castle was a Developer Advocate at Render.

Subscribe to our newsletter for regular product updates.

Discover More

  1. How Render Scaled Knative to Support 100k+ Free-Tier Apps

    As Render free-tier apps exploded in popularity, we needed to make the feature much more scalable. This work was our first step along that path.

    - Hieu Nguyen

  2. Render design doc: Reducing Free-tier networking footprint

    An in-depth supplement for the post 'How Render scaled Knative to support 100k+ Free-tier apps'

    - Hieu Nguyen

  3. Deploy prebuilt Docker images to Render

    Render now supports deploying Docker images directly from your container registry.

    - Stephen Barlow

  4. Announcing Point-in-Time Recovery

    With Point-in-Time Recovery enabled for your Render PostgreSQL, if you and your team experience unexpected data loss, you can restore to a new database seeded with data from archiv…

    - Scott Numamoto