Skip to content

Repository files navigation

@plutotcool/astro-password-protect

Password-gate any Astro site behind a signed, HMAC-based session cookie. A small library: a middleware factory you compose in your own src/middleware.ts, plus the auth helpers to back a login page. It ships no UI, so the page stays yours.

Runtime-neutral (WebCrypto only), so it runs on Node, Cloudflare Workers, Deno and Bun without a compat flag.

Usage

Declare the SITE_PASSWORD secret in your env schema:

// astro.config.mjs
import { defineConfig, envField } from 'astro/config'

export default defineConfig({
  env: {
    schema: {
      SITE_PASSWORD: envField.string({
        context: 'server',
        access: 'secret',
        optional: true,
      }),
    },
  },
})

Compose the gate in your middleware:

// src/middleware.ts
import { sequence } from 'astro:middleware'
import passwordProtect from '@plutotcool/astro-password-protect'

export const onRequest = sequence(passwordProtect())

Add a login page at the gate's loginPath (default /login), backed by the helpers:

---
// src/pages/login.astro
import {
  getPassword,
  verifyPassword,
  setSession,
  hasValidSession,
} from '@plutotcool/astro-password-protect'

export const prerender = false

const secret = getPassword()
// … read the form, call verifyPassword / setSession / hasValidSession …
---

The password is read at runtime from the SITE_PASSWORD server secret, and the gate is a no-op when it is empty — an unconfigured environment is never blocked.

The gate is server-side only

It runs in middleware, on request, so it only covers routes rendered on demand:

  • a fully static build (no adapter) has no server at runtime — nothing is gated;
  • prerendered routes in a hybrid build are skipped, since they are built once, ahead of any request;
  • pages you want behind the gate must be prerender = false, and the site needs an adapter.

Set output accordingly, or opt individual routes out of prerendering. Static assets are served without the gate in every case.

Options

Option Default Description
exclude [] Path prefixes always served without the gate (static assets are always excluded).
bypass — (context) => boolean | Promise<boolean> — let a request through when it returns true.
loginPath '/login' Path the gate redirects to, and where your login page lives.

bypass keeps the package agnostic. To let a CMS live-preview session through:

export const onRequest = sequence(
  passwordProtect({
    exclude: ['/api/preview'],
    bypass: (context) => context.locals.preview,
  }),
)

Compose so that whatever sets the bypass flag runs first — an integration-injected pre middleware (e.g. a CMS preview) already runs before your src/middleware.ts.

About

🔒 - A middleware for Astro to easily setup password protection

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages