Password Protection

Secure your static sites with password authentication

Protect your Forgejo Pages sites with secure password authentication.

Overview

The password protection feature allows you to require authentication before users can access your site. It uses:

  • SHA256 password hashing - Passwords never stored in plaintext
  • HMAC-signed cookies - Prevents cookie tampering
  • Secure cookies - HttpOnly, Secure (HTTPS), SameSite=Strict
  • Beautiful login UI - Gradient design with centred form

Quick Setup

Step 1: Generate Password Hash

echo -n "your-password-here" | shasum -a 256

Example output:

5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

Step 2: Add to .pages File

enabled: true
password: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

Step 3: Configure Traefik (Optional)

http:
  middlewares:
    pages-server:
      plugin:
        pages-server:
          pagesDomain: pages.example.com
          forgejoHost: https://git.example.com
          authCookieDuration: 3600
          authSecretKey: "randomly-generated-secret-key"

Step 4: Commit and Push

git add .pages
git commit -m "Add password protection"
git push

Advanced Configuration

authCookieDuration: 14400  # 4 hours in seconds

Recommendations:

  • Public sites: 1-4 hours (3600-14400)
  • Private sites: 8-24 hours (28800-86400)
  • Internal sites: 7 days (604800)
openssl rand -base64 32
authSecretKey: "your-random-secret-here"

Password Generation Methods

Using shasum (Mac/Linux)

echo -n "mypassword" | shasum -a 256

Using OpenSSL

openssl rand -base64 16
echo -n "your-password" | openssl dgst -sha256

Using Python

import hashlib
password = "mypassword"
hash_object = hashlib.sha256(password.encode())
print(hash_object.hexdigest())

Using Node.js

const crypto = require('crypto');
const password = 'mypassword';
const hash = crypto.createHash('sha256').update(password).digest('hex');
console.log(hash);

Login Page

When users visit a password-protected site, they see:

  • 🎨 Purple gradient background
  • 📱 Responsive design
  • 🔍 Repository name displayed
  • ⚠️ Error messages for wrong passwords
  • ⌨️ Auto-focus on password field
  • 🔒 Secure HTTPS-only form submission

How It Works

  1. User visits protected site
  2. Plugin checks for authentication cookie
  3. No cookie found → Show login page
  4. User enters password
  5. Password hashed with SHA256
  6. Hash compared with stored hash
  7. Match → Set signed cookie, redirect to site
  8. No match → Show error message

Security Features

Password Hashing

  • Passwords stored as SHA256 hashes in .pages file
  • Original password never stored
  • One-way hashing prevents password recovery
  • HttpOnly: JavaScript cannot access cookies (XSS protection)
  • Secure: Only sent over HTTPS connections
  • SameSite=Strict: Prevents CSRF attacks
  • HMAC Signature: Prevents cookie tampering (when authSecretKey configured)

Cache TTL

  • Password hashes cached for 60 seconds
  • Reduces .pages file reads
  • Automatic cache refresh every minute
  • No password stored in cache (only hash)

Multiple Protected Sites

Each repository gets its own authentication:

Cookie: pages_auth_username_repo1  # For repo1
Cookie: pages_auth_username_repo2  # For repo2

Users must authenticate separately for each protected repository.

Removing Protection

Remove the password: line from .pages:

enabled: true
# password: removed

Wait up to 60 seconds for cache to expire, or clear cache manually.

Troubleshooting

Login page doesn’t appear

Solutions:

  1. Verify password: field exists in .pages file
  2. Check hash is valid SHA256 (64 hex characters)
  3. Wait 60 seconds for cache to update
  4. Clear password cache: redis-cli DEL "password:username:repository"

Wrong password error even with correct password

Solutions:

  1. Verify using hash in .pages, not plaintext
  2. Check for extra spaces/newlines in hash
  3. Re-generate hash: echo -n "password" | shasum -a 256
  4. Ensure exact password match (case-sensitive)

Solutions:

  1. Ensure site served over HTTPS
  2. Check browser allows cookies
  3. Verify authCookieDuration is positive number
  4. Check browser cookie settings

Getting redirected after login

Solutions:

  1. Clear browser cookies for the site
  2. Check authSecretKey hasn’t changed
  3. Verify system clock is accurate
  4. Check browser JavaScript is enabled

Best Practices

  1. Use strong passwords - 16+ characters, mixed case, numbers, symbols
  2. Configure authSecretKey - Enables HMAC cookie signing
  3. Set appropriate cookie duration - Balance security vs. convenience
  4. Use HTTPS - Required for secure cookies
  5. Rotate passwords - Change periodically for sensitive sites
  6. Monitor access - Check logs for failed login attempts

Example Configurations

Basic Protection

enabled: true
password: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

With Custom Domain

enabled: true
custom_domain: private.example.com
password: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

High Security (Short Duration)

Traefik config:

authCookieDuration: 1800  # 30 minutes
authSecretKey: "long-random-secret-key"

.pages:

enabled: true
password: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8