# How LunaTV Manages Authentication: Cookie-Based Security with HMAC Signatures

> Discover how LunaTV secures user access with its robust cookie-based authentication system. Learn about HMAC signatures and Next.js middleware for enhanced security.

- Repository: [MoonTechLab/LunaTV](https://github.com/MoonTechLab/LunaTV)
- Tags: internals
- Published: 2026-09-09

---

**LunaTV implements a dual-mode cookie authentication system that either stores a raw password for local-storage deployments or generates HMAC-SHA-256 signed tokens for database-backed environments, with all requests validated through Next.js middleware.**

The LunaTV project (`MoonTechLab/LunaTV`) provides a flexible authentication layer designed to adapt across multiple storage backends including local-storage, Redis, Upstash, and Kvrocks. The implementation balances simplicity for single-user instances with cryptographic security for multi-user productions, utilizing signed cookie tokens and environment-based secrets.

## Login Flow and Cookie Generation

The authentication process begins at the `/api/login` endpoint defined in [`src/app/api/login/route.ts`](https://github.com/MoonTechLab/LunaTV/blob/main/src/app/api/login/route.ts). This route handles credential verification differently depending on the configured storage mode.

### Local-Storage Mode

In local-storage mode, the system performs a direct password comparison against the `PASSWORD` environment variable. Upon successful validation, the `generateAuthCookie` function creates a cookie containing the raw password and user role.

```typescript
// POST /api/login (local-storage mode)
const { password } = await req.json();
if (password === process.env.PASSWORD) {
  const cookie = await generateAuthCookie(undefined, password, 'user', true);
  const resp = NextResponse.json({ ok: true });
  resp.cookies.set('auth', cookie, { path: '/', expires: /* 7 days */ });
  return resp;
}

```

### Database Mode with Cryptographic Signing

For Redis, Upstash, or Kvrocks backends, credentials are verified via `db.verifyUser`. Successful authentication generates a cookie that **excludes the password** but includes the username, a cryptographic **HMAC-SHA-256 signature** of the username (using `PASSWORD` as the secret), a timestamp, and the user's role. The payload is URL-encoded JSON.

```typescript
const { username, password } = await req.json();
const ok = await db.verifyUser(username, password);
if (ok) {
  const cookie = await generateAuthCookie(username, undefined, user.role);
  const resp = NextResponse.json({ ok: true });
  resp.cookies.set('auth', cookie, { path: '/', expires: /* 7 days */ });
  return resp;
}

```

## Cookie Extraction and Validation

The [`src/lib/auth.ts`](https://github.com/MoonTechLab/LunaTV/blob/main/src/lib/auth.ts) file provides the core utilities for parsing authentication state. The `getAuthInfoFromCookie` function reads the `auth` cookie server-side, decodes the URL-encoded value, and parses the JSON payload. For client-side usage, `getAuthInfoFromBrowserCookie` performs identical operations using `document.cookie`.

## Middleware Enforcement and Signature Verification

The global middleware in [`src/middleware.ts`](https://github.com/MoonTechLab/LunaTV/blob/main/src/middleware.ts) intercepts all protected routes to enforce authentication policies. It first checks `shouldSkipAuth` to bypass static or public paths, then validates the cookie payload.

### Validation Logic

In local-storage mode, the middleware simply verifies that the stored password matches `process.env.PASSWORD`. For database modes, it requires both a `username` and `signature` field.

```typescript
const authInfo = getAuthInfoFromCookie(request);
if (!authInfo?.username || !authInfo?.signature) return handleAuthFailure(...);
const isValid = await verifySignature(
  authInfo.username,
  authInfo.signature,
  process.env.PASSWORD!
);
if (!isValid) return handleAuthFailure(...);

```

The `verifySignature` function recreates the HMAC key from the `PASSWORD` environment variable and validates the supplied signature against the username. Invalid or missing credentials result in **401** responses or redirects to the login page.

## Security Architecture

The LunaTV authentication system implements several protective measures:

- **Password Isolation**: In non-local-storage modes, passwords never persist in cookies.
- **Cryptographic Integrity**: HMAC-SHA-256 signatures prevent tampering with the username field.
- **Replay Protection**: The `auth.timestamp` field mitigates replay attacks by allowing token expiration checks.
- **Role-Based Access**: Cookies include a `role` field parsed from [`src/lib/config.ts`](https://github.com/MoonTechLab/LunaTV/blob/main/src/lib/config.ts) for authorization decisions.

## Summary

- LunaTV supports both simple password storage and cryptographically signed tokens via [`src/app/api/login/route.ts`](https://github.com/MoonTechLab/LunaTV/blob/main/src/app/api/login/route.ts).
- The `generateAuthCookie` function creates HMAC-SHA-256 signed payloads for database modes, while local-storage mode stores raw passwords.
- [`src/middleware.ts`](https://github.com/MoonTechLab/LunaTV/blob/main/src/middleware.ts) enforces authentication globally, verifying signatures using `verifySignature` and the `PASSWORD` environment secret.
- Cookie parsing utilities in [`src/lib/auth.ts`](https://github.com/MoonTechLab/LunaTV/blob/main/src/lib/auth.ts) handle both server-side request objects and client-side `document.cookie`.

## Frequently Asked Questions

### How does LunaTV store passwords in authentication cookies?

In local-storage mode, LunaTV stores the raw password in the cookie. For database-backed modes (Redis, Upstash, Kvrocks), the cookie stores only the username, role, timestamp, and an HMAC-SHA-256 signature of the username—never the password itself.

### What prevents attackers from forging authentication cookies?

The system uses **HMAC-SHA-256 signatures** generated with the `PASSWORD` environment variable as the secret key. The `verifySignature` function in the middleware recalculates the expected signature for the provided username; any tampering with the cookie payload invalidates the signature, causing immediate rejection.

### How does LunaTV handle authentication across different storage backends?

The [`src/lib/db.ts`](https://github.com/MoonTechLab/LunaTV/blob/main/src/lib/db.ts) abstraction layer provides `db.verifyUser` for credential validation against Redis, Upstash, or Kvrocks. The [`src/lib/config.ts`](https://github.com/MoonTechLab/LunaTV/blob/main/src/lib/config.ts) file loads user configurations including roles and ban status. Local-storage mode bypasses the database entirely, comparing credentials directly against the `PASSWORD` environment variable.

### Can the authentication tokens be replayed by attackers?

Each signed cookie includes a `timestamp` field that enables replay attack mitigation. While the source code stores this timestamp, implementations can validate token age against current server time to reject expired or reused tokens from previous sessions.