# How to Configure Remote Access with HTTP Basic Auth in Pi Web

> Secure your Pi Web remote access by configuring HTTP Basic Auth. Learn how to set the PI_WEB_PASSWORD environment variable for easy authentication.

- Repository: [Alex Yang/pi-web](https://github.com/agegr/pi-web)
- Tags: how-to-guide
- Published: 2026-08-14

---

**Set the `PI_WEB_PASSWORD` environment variable to enable HTTP Basic authentication for Pi Web; the username is always `pi`.**

Pi Web is a lightweight Next.js application that secures remote access through a custom middleware architecture. The **[`proxy.ts`](https://github.com/agegr/pi-web/blob/main/proxy.ts)** middleware enforces HTTP Basic authentication by validating credentials against environment variables, with the actual verification logic implemented in **[`web-auth.ts`](https://github.com/agegr/pi-web/blob/main/web-auth.ts)**. This guide walks through the complete configuration process based on the agegr/pi-web source code.

## How HTTP Basic Auth Works in Pi Web

The authentication flow follows a strict two-stage pipeline. First, the **request-security** module validates whether the incoming request originates from a trusted source. Only after passing that check does the proxy middleware evaluate the Web Password configuration.

In [`proxy.ts`](https://github.com/agegr/pi-web/blob/main/proxy.ts) (lines 25-30), the middleware reads `PI_WEB_PASSWORD` from process environment variables. When this variable is defined and non-empty, every matching request must include a valid `Authorization: Basic ...` header.

The validation occurs in [`lib/web-auth.ts`](https://github.com/agegr/pi-web/blob/main/lib/web-auth.ts) through the `isValidBasicAuthorization` function. This helper:
- Parses and base-64-decodes the header
- Extracts username and password components
- Compares against the hard-coded username `pi` (`PI_WEB_AUTH_USERNAME`) and your configured password
- Uses `crypto.timingSafeEqual` for hash comparison to prevent timing attacks

If credentials are missing or invalid, the middleware returns **401 Unauthorized** with a `WWW-Authenticate: Basic` challenge header (lines 31-37 of [`proxy.ts`](https://github.com/agegr/pi-web/blob/main/proxy.ts)). Valid requests proceed via `NextResponse.next()`.

## Enabling HTTP Basic Auth

### 1. Set the Password Environment Variable

Create or edit `.env` in your project root:

```bash
PI_WEB_PASSWORD=your-strong-password

```

The username is permanently fixed to `pi`. Attempting to authenticate with any other username will fail regardless of password correctness.

### 2. Start the Server

```bash
npm install
npm run dev

```

The development server launches on port 30141 with Basic Auth enforced for all matched routes.

### 3. Verify Authentication

Test access via `curl`:

```bash
curl -u pi:your-strong-password http://localhost:30141/

```

Or open `http://localhost:30141/` in a browser. The browser will prompt for credentials—enter `pi` as the username.

## Disabling Authentication for Local Development

To disable Basic Auth entirely, either:
- Omit `PI_WEB_PASSWORD` from your environment
- Set it to an empty string

```bash

# .env — development mode

# PI_WEB_PASSWORD=

```

The middleware performs a truthiness check: when `PI_WEB_PASSWORD` is falsy, the Basic Auth block is bypassed and requests proceed directly to downstream handlers.

## Customizing Protected Routes

Control which paths require authentication by modifying the `matcher` configuration in [`proxy.ts`](https://github.com/agegr/pi-web/blob/main/proxy.ts):

```typescript
export const config = {
  matcher: ["/", "/api/:path*"]
};

```

Common customization patterns:
- **Protect only API routes**: `matcher: ["/api/:path*"]`
- **Exclude static assets**: `matcher: ["/", "/api/:path*", "/admin/:path*"]`
- **Protect entire application**: `matcher: ["/:path*"]`

The matcher uses Next.js middleware path syntax. Changes take effect immediately on server restart.

## Security Implementation Details

### Timing-Safe Comparison

The `hashSecret` function in [`web-auth.ts`](https://github.com/agegr/pi-web/blob/main/web-auth.ts) applies SHA-256 to both supplied and expected passwords before comparison. This ensures that `crypto.timingSafeEqual` operates on fixed-length buffers, preventing byte-by-byte timing attacks that could leak password length or content.

### Base-64 Integrity Check

The `isValidBasicAuthorization` function validates that the header can be round-trip decoded:

```typescript
if (Buffer.from(decoded, "base64").toString("base64") !== base64Credentials) {
  return false;
}

```

This catches malformed headers that might exploit decoding ambiguities.

### Fail-Fast Design

The authentication check short-circuits when `PI_WEB_PASSWORD` is unset. This intentional design allows zero-configuration local development while ensuring production deployments fail closed when the password is configured.

## Authentication Request Flow Summary

1. Request arrives at Next.js edge runtime
2. [`proxy.ts`](https://github.com/agegr/pi-web/blob/main/proxy.ts) middleware intercepts via `matcher` patterns
3. [`request-security.ts`](https://github.com/agegr/pi-web/blob/main/request-security.ts) checks host/ip allowlists
4. If `PI_WEB_PASSWORD` is set, `isValidBasicAuthorization` validates credentials
5. On failure: 401 response with `WWW-Authenticate: Basic` header
6. On success: `NextResponse.next()` delegates to page/API handlers

## Summary

- **HTTP Basic Auth in Pi Web** is controlled exclusively by the `PI_WEB_PASSWORD` environment variable
- **Username is fixed to `pi`** and cannot be customized
- **Password validation uses timing-safe hashing** via `crypto.timingSafeEqual` in [`lib/web-auth.ts`](https://github.com/agegr/pi-web/blob/main/lib/web-auth.ts)
- **Route protection scope** is configured through the `matcher` export in [`proxy.ts`](https://github.com/agegr/pi-web/blob/main/proxy.ts)
- **Development convenience**: omit `PI_WEB_PASSWORD` to disable authentication entirely

## Frequently Asked Questions

### What is the default username for Pi Web Basic Auth?

The username is hard-coded to **`pi`** via the `PI_WEB_AUTH_USERNAME` constant in [`web-auth.ts`](https://github.com/agegr/pi-web/blob/main/web-auth.ts). This cannot be changed through configuration—only the password is customizable.

### How do I change which routes require authentication?

Edit the `config.matcher` export in [`proxy.ts`](https://github.com/agegr/pi-web/blob/main/proxy.ts). The array supports Next.js middleware path patterns including wildcards (`:path*`) and specific segments. Restart the server after modifying this configuration.

### Why does my password work in some browsers but not others?

Ensure you are using `pi` as the username. Some browsers cache credentials aggressively; try clearing stored passwords or using an incognito window. The `curl` test with explicit `-u pi:password` is the most reliable verification method.

### Is the password transmitted securely?

HTTP Basic Auth transmits credentials base-64-encoded but **not encrypted**. Always deploy Pi Web behind HTTPS in production environments—TLS encryption protects the Authorization header in transit. The base-64 encoding is not a security mechanism; it merely formats credentials for the header specification.