Password-protect your Vercel sites.
No $150/month required.

Open source middleware (or proxy on Next 16+) for Next.js. Protect your entire site or specific routes. Works on Vercel's free Hobby plan.

pnpm add @tommyvez/passfort

Try it

Run each step in order: set env in the terminal (simulated — this site already has them), then request the protected /demo route. You’ll see 401 until you enter the password and authenticate; then the session cookie lets you through.

Terminal
# Run each step in order. Set env, then request the protected route.
Set password

Why passfort

  • Free. No subscription. Works on Vercel Hobby.
  • Secure. PBKDF2-SHA256, HMAC cookies, timing-safe compare.
  • Edge. Runs before your app. No cold starts.
  • Flexible. Protect routes or whole site. Custom form or your own.

vs Vercel Pro

passfort
Vercel Pro
Cost
$0
$150/month
Password Protection
Custom Form Design
Route-Specific Protection
✗ (entire deployment)
Open Source
Works on Hobby Plan

Documentation

Quick start

  1. Install. pnpm add @tommyvez/passfort or npm install @tommyvez/passfort
  2. Add middleware or proxy. Create or update middleware.ts (or proxy.ts on Next 16+) at your project root.

    Option A — entire site (no routes to list): use protectAll: true and one matcher. Run npx passfort matcher (or npx passfort matcher --proxy for Next 16+) to print a ready-to-paste snippet.

    import { withPasswordProtect } from '@tommyvez/passfort/next';
    
    export default withPasswordProtect({ protectAll: true });
    
    export const config = {
      matcher: ['/((?!api|_next|favicon.ico).*)'],
    };

    Next 16+ (proxy): use proxy.ts and export const proxy = withPasswordProtect({ ... }). Same options; run npx passfort matcher --proxy for the snippet.

    Option B — specific paths only:

    import { withPasswordProtect } from '@tommyvez/passfort/next';
    
    export default withPasswordProtect({
      paths: ['/admin', '/preview', '/dashboard'],
    });
    
    export const config = {
      matcher: ['/admin/:path*', '/preview/:path*', '/dashboard/:path*'],
    };
  3. Set environment variables in Vercel (Settings → Environment Variables):
    • PASSFORT_SECRET — min 16 chars, for session signing (e.g. openssl rand -base64 24)
    • PASSFORT_PASSWORD — plain password for quick start, or PASSFORT_HASH for production (use npx passfort hash "your-password")
  4. Deploy. Your protected routes now require a password.

CLI: From your Next.js project root, npx passfort init creates middleware.ts (entire site). Use npx passfort init --proxy for Next 16+ (proxy.ts), npx passfort init --paths=/admin,/foo for specific paths, or npx passfort init --block for maintenance mode (see below). To paste a snippet manually: npx passfort matcher, npx passfort matcher --proxy, or npx passfort matcher --block.

Block all routes (no password)

Maintenance mode — block everyone with no form or input. Matched routes get 503. No password or secret required.

  • Automated: npx passfort init --block (or npx passfort init --block --proxy for Next 16+) creates middleware/proxy that returns 503 when PASSFORT_BLOCK_ONLY=true.
  • Manual: Run npx passfort matcher --block (or npx passfort matcher --block --proxy) and paste the output into middleware.ts or proxy.ts. Set PASSFORT_BLOCK_ONLY=true in Vercel.

Remove PASSFORT_BLOCK_ONLY and redeploy to restore access.

Removing protection

Without code changes: Set PASSFORT_ENABLED=false (or 0) in Vercel, redeploy. Protection is off; middleware/proxy stays in place. Set back to true or remove the var and redeploy to re-enable.

Remove protection entirely:

  1. Revert middleware.ts or proxy.ts to your previous handler (or delete the withPasswordProtect wrapper and export your own).
  2. Remove PASSFORT_PASSWORD, PASSFORT_HASH, and PASSFORT_SECRET from Vercel environment variables.
  3. Redeploy. Your app is unchanged; only the protection layer is gone.

Full docs on GitHub npx passfort init, npx passfort init --proxy, npx passfort matcher, npx passfort matcher --proxy, npx passfort matcher --block, protect entire site, block-only (maintenance) mode, PASSFORT_ENABLED, custom form, HTTP Basic Auth, custom login page.

Support

Free and open source. If it helps you, consider supporting development.