# How to Implement Password Protection Using the ACCESS_KEYS Environment Variable in MiniSearch

> Implement password protection in MiniSearch using the ACCESS_KEYS environment variable. Secure API endpoints with Argon2 validation and prompt users for authentication.

- Repository: [Victor Nogueira/minisearch](https://github.com/felladrin/minisearch)
- Tags: how-to-guide
- Published: 2026-03-01

---

**MiniSearch enables instant password protection when you define the `ACCESS_KEYS` environment variable, activating Argon2-based validation that secures all API endpoints while the UI prompts users for authentication and persists valid sessions in localStorage.**

The felladrin/minisearch repository ships with a built-in access control system that requires zero code changes to deploy. By setting a single environment variable, you activate server-side key validation using Argon2 hashing and client-side session management. This implementation protects search, inference, and custom endpoints behind a password-style access key system.

## How the ACCESS_KEYS Protection System Works

MiniSearch uses a multi-layered approach to access control that spans both server and client codebases. When `ACCESS_KEYS` is populated, the system automatically activates validation hooks and UI prompts.

### Server-Side Validation Architecture

The server intercepts all requests through the `validateAccessKeyServerHook` middleware defined in [`server/validateAccessKeyServerHook.ts`](https://github.com/felladrin/minisearch/blob/main/server/validateAccessKeyServerHook.ts). This hook listens for POST requests to `/api/validate-access-key` and compares submitted hashes against the environment variable using Argon2 verification.

The validation logic loops through each key in the comma-separated list:

```typescript
const accessKeys = process.env.ACCESS_KEYS?.split(",") ?? [];

for (const key of accessKeys) {
  if (await argon2Verify({ password: key, hash: accessKeyHash })) {
    isValid = true;
    break;
  }
}

```

If any key matches the submitted Argon2 hash, the server returns `{ valid: true }`, granting access to the requesting client.

### Client-Side Authentication Flow

The client application checks for protection status through the `VITE_ACCESS_KEYS_ENABLED` flag exposed in [`vite.config.ts`](https://github.com/felladrin/minisearch/blob/main/vite.config.ts). When enabled, the `App` component in [`client/components/App/App.tsx`](https://github.com/felladrin/minisearch/blob/main/client/components/App/App.tsx) forces a modal prompt before rendering the main interface.

User input flows through [`client/modules/accessKey.ts`](https://github.com/felladrin/minisearch/blob/main/client/modules/accessKey.ts), which handles three critical operations:

- **Local Hashing**: Plain-text keys are hashed locally using `hashAccessKey()` before transmission
- **Server Validation**: The hash is sent to `/api/validate-access-key` for verification
- **Session Persistence**: Valid hashes are stored in `localStorage` under `accessKeyHash` with timestamps to prevent re-prompting during the timeout period defined by `VITE_ACCESS_KEY_TIMEOUT_HOURS`

## Configuring Password Protection

Activating access control requires only environment configuration and a service restart. No source code modifications are necessary.

### 1. Define Access Keys in the Environment

Create or edit the `.env` file at the project root using the format shown in `.env.example`. Set `ACCESS_KEYS` to a comma-separated list of plain-text passwords:

```text

# .env

ACCESS_KEYS="alpha-2024,beta-2024,gamma-2024"

```

Each comma-separated value represents a valid access credential. The server stores these as plain text in memory but validates them against Argon2 hashes submitted by clients.

### 2. Enable the Vite Build Flag

The build system automatically detects the environment variable and exposes it to the client bundle. In [`vite.config.ts`](https://github.com/felladrin/minisearch/blob/main/vite.config.ts), the `define` block sets `VITE_ACCESS_KEYS_ENABLED`:

```typescript
define: {
  VITE_ACCESS_KEYS_ENABLED: JSON.stringify(
    Boolean(process.env.ACCESS_KEYS)
  ),
},

```

This boolean flag determines whether the UI renders the access key prompt or bypasses authentication entirely.

### 3. Rebuild and Deploy

For Docker deployments, rebuild the image to capture the new environment variables:

```bash
docker compose up --build -d

```

The server hook activates automatically on startup when `process.env.ACCESS_KEYS` is detected.

### 4. Client Authentication Implementation

When integrating the access key flow into custom client code, import the validation module from [`client/modules/accessKey.ts`](https://github.com/felladrin/minisearch/blob/main/client/modules/accessKey.ts):

```typescript
import { validateAccessKey } from "./accessKey";

async function onKeySubmit(input: string) {
  const ok = await validateAccessKey(input);
  if (ok) {
    // Proceed to protected resources
    console.log("Access granted");
  } else {
    // Display authentication error
    console.error("Invalid access key");
  }
}

```

The `validateAccessKey` function handles local hashing, server verification, and automatic localStorage persistence upon success.

## Key Source Files Reference

Understanding the codebase structure helps with customization and debugging:

- **[`server/validateAccessKeyServerHook.ts`](https://github.com/felladrin/minisearch/blob/main/server/validateAccessKeyServerHook.ts)**: Implements the POST `/api/validate-access-key` endpoint and performs Argon2 verification against `ACCESS_KEYS`
- **[`client/modules/accessKey.ts`](https://github.com/felladrin/minisearch/blob/main/client/modules/accessKey.ts)**: Contains `hashAccessKey()`, `validateAccessKey()`, and `verifyStoredAccessKey()` for client-side operations
- **[`client/components/App/App.tsx`](https://github.com/felladrin/minisearch/blob/main/client/components/App/App.tsx)**: UI entry point that conditionally renders the access key modal based on `VITE_ACCESS_KEYS_ENABLED`
- **[`vite.config.ts`](https://github.com/felladrin/minisearch/blob/main/vite.config.ts)**: Build configuration that exposes the access key feature flag to the client
- **[`docs/configuration.md`](https://github.com/felladrin/minisearch/blob/main/docs/configuration.md)**: Official documentation for environment variables
- **`.env.example`**: Template showing expected variable format

## Summary

- Set the `ACCESS_KEYS` environment variable to a comma-separated list of authorized passwords to activate protection
- The server automatically validates keys using Argon2 through [`server/validateAccessKeyServerHook.ts`](https://github.com/felladrin/minisearch/blob/main/server/validateAccessKeyServerHook.ts)
- The client UI switches to protected mode via `VITE_ACCESS_KEYS_ENABLED` defined in [`vite.config.ts`](https://github.com/felladrin/minisearch/blob/main/vite.config.ts)
- Valid sessions persist in `localStorage` with configurable timeouts via `VITE_ACCESS_KEY_TIMEOUT_HOURS`
- All API endpoints, including search and inference, require valid access keys when protection is enabled

## Frequently Asked Questions

### What hashing algorithm does MiniSearch use for access key validation?

MiniSearch uses **Argon2** for all access key operations. When a user enters a key, the client hashes it locally using `hashAccessKey()` from [`client/modules/accessKey.ts`](https://github.com/felladrin/minisearch/blob/main/client/modules/accessKey.ts) before transmission. The server then uses `argon2Verify()` in [`server/validateAccessKeyServerHook.ts`](https://github.com/felladrin/minisearch/blob/main/server/validateAccessKeyServerHook.ts) to compare the submitted hash against the plain-text keys defined in `ACCESS_KEYS` without transmitting passwords over the network.

### Can I use ACCESS_KEYS with Docker Compose?

Yes. Pass the environment variable through your [`docker-compose.yml`](https://github.com/felladrin/minisearch/blob/main/docker-compose.yml) file or an `.env` file in the project root. The container must be rebuilt or restarted to pick up changes to `ACCESS_KEYS`. You can reference the variable in your compose file using `${ACCESS_KEYS:-}` to provide a default empty value if the variable is unset.

### How long do access key sessions last?

Session duration is controlled by the `VITE_ACCESS_KEY_TIMEOUT_HOURS` environment variable. After successful validation, the client stores the hash and timestamp in `localStorage`. The `verifyStoredAccessKey()` function in [`client/modules/accessKey.ts`](https://github.com/felladrin/minisearch/blob/main/client/modules/accessKey.ts) checks this timeout on page load and prompts for re-authentication when the period expires.

### Does enabling ACCESS_KEYS affect API endpoints only, or the UI as well?

Both. When `ACCESS_KEYS` is defined, [`vite.config.ts`](https://github.com/felladrin/minisearch/blob/main/vite.config.ts) sets `VITE_ACCESS_KEYS_ENABLED` to true, causing [`client/components/App/App.tsx`](https://github.com/felladrin/minisearch/blob/main/client/components/App/App.tsx) to render the access key modal before the main interface. Simultaneously, the server hook validates keys for all requests. The system protects both the user interface and underlying API resources.