# Server-Side Cookie Storage Mechanism Using CookieStore in wechat-article-exporter

> Discover the server-side cookie storage mechanism in wechat-article-exporter using CookieStore. Learn how it combines memory cache and Nitro KV storage for efficient WeChat MP authentication cookie management.

- Repository: [公众号文章工具箱/wechat-article-exporter](https://github.com/wechat-article/wechat-article-exporter)
- Tags: internals
- Published: 2026-05-26

---

**The wechat-article-exporter project implements a hybrid server-side cookie storage mechanism using CookieStore that combines an in-memory LRU cache with persistent Nitro KV storage to manage WeChat MP authentication cookies.**

The wechat-article-exporter repository handles sensitive WeChat "MP" authentication data that must persist across serverless invocations while maintaining high performance. The server-side cookie storage mechanism uses a two-layer approach defined in [`server/utils/CookieStore.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/utils/CookieStore.ts) to balance access speed with cross-instance durability.

## Architecture Overview

The **CookieStore** implements a hybrid storage strategy that prioritizes low-latency access while ensuring persistence across distributed deployments. When the server receives authentication cookies from the WeChat API, they are simultaneously cached in memory and written to Nitro KV storage.

### In-Memory LRU Cache Layer

At the core of the mechanism sits a native JavaScript **Map** that stores `AccountCookie` instances keyed by the user's **auth-key** (a UUID string). This map preserves insertion order and implements LRU (Least Recently Used) eviction through access-time tracking.

Key characteristics of the cache layer:

- **Maximum capacity**: Defaults to 1000 entries before automatic eviction occurs
- **Access pattern**: Methods like `getAccountCookie`, `getCookie`, and `setCookie` move accessed entries to the map's tail, ensuring frequently used sessions remain hot
- **Eviction policy**: When the cache exceeds `maxSize`, the oldest entry is removed via `evictIfNeeded` to prevent unbounded memory growth

### Persistent KV Storage Fallback

When a cookie is not found in the in-memory cache, the system falls back to **Nitro KV storage** (e.g., Cloudflare KV) via the helper functions `getMpCookie` and `setMpCookie` defined in [`server/kv/cookie.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/kv/cookie.ts). This layer provides durability across serverless function cold starts and deployment restarts.

Implementation details:

- **Key namespace**: All entries are stored under the `cookie:` prefix to avoid collisions
- **Time-to-live**: Entries automatically expire after four days using the `expirationTtl` parameter
- **Deserialization**: Raw KV values are reconstructed into `AccountCookie` instances via the static `AccountCookie.create` method

## Core Components

### AccountCookie Parser

The **`AccountCookie`** class, located in [`server/utils/CookieStore.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/utils/CookieStore.ts) (lines 8-31), handles the intricate parsing of raw `set-cookie` headers from WeChat's authentication responses. It transforms HTTP header strings into structured `CookieEntity` arrays and can regenerate proper `Cookie` header strings for forwarding to upstream endpoints.

### CookieStore Orchestration

The **`CookieStore`** class (lines 9-94 in [`server/utils/CookieStore.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/utils/CookieStore.ts)) exposes the public API for cookie management. It orchestrates bidirectional synchronization between the LRU cache and KV storage, providing methods including `getCookie`, `setCookie`, `removeCookie`, and `getToken`.

Convenience helpers abstract the lookup logic for API layers:

- **`getCookieFromStore`**: Retrieves ready-to-forward `Cookie` header strings by inspecting the `X-Auth-Key` header or `auth-key` cookie from the incoming request
- **`getTokenFromStore`**: Extracts the associated login token for session validation

## Practical Implementation Patterns

### Storing Authentication Cookies

When a user completes the WeChat login flow, the server receives `set-cookie` headers from the upstream API. The system persists these using `cookieStore.setCookie(authKey, token, rawCookies)`, which populates both the in-memory cache and the KV backing store.

```typescript
// Example: server/api/web/mp/login/bizlogin.post.ts
import { cookieStore } from '~/server/utils/CookieStore';
import type { H3Event } from 'h3';

async function handleLogin(event: H3Event, token: string, setCookieHeaders: string[]) {
  const authKey = event.headers['x-auth-key'] ?? generateUuid();
  await cookieStore.setCookie(authKey, token, setCookieHeaders);
  return { authKey }; // Returned to client for subsequent requests
}

```

### Retrieving Cookies for Proxy Requests

For each subsequent API request, the server retrieves stored cookies to forward to WeChat endpoints. The `getCookieFromStore` function handles the auth-key extraction and returns the appropriate Cookie header string.

```typescript
import { getCookieFromStore } from '~/server/utils/CookieStore';
import type { H3Event } from 'h3';

export async function proxyRequest(event: H3Event, upstreamUrl: string) {
  const cookieHeader = await getCookieFromStore(event);
  const response = await fetch(upstreamUrl, {
    method: event.method,
    headers: {
      ...event.headers,
      ...(cookieHeader ? { cookie: cookieHeader } : {})
    },
    body: event.body
  });
  return response;
}

```

### Session Invalidation

Explicit removal occurs through `cookieStore.removeCookie(authKey)`, which clears the entry from both the Map and KV storage. This is typically invoked during logout operations to prevent cookie reuse.

```typescript
import { cookieStore } from '~/server/utils/CookieStore';

export async function logout(event: H3Event) {
  const authKey = event.headers['x-auth-key'] ?? parseCookies(event)['auth-key'];
  if (authKey) {
    await cookieStore.removeCookie(authKey);
  }
}

```

## Summary

- The **CookieStore** implements a hybrid server-side cookie storage mechanism combining in-memory LRU caching with Nitro KV persistence in [`server/utils/CookieStore.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/utils/CookieStore.ts).
- **AccountCookie** handles parsing and serialization of raw cookie headers into structured entities for transportation.
- The in-memory cache defaults to **1000 entries** with automatic LRU eviction, while KV entries expire after **four days** to ensure stale credentials do not linger.
- Helper functions `getCookieFromStore` and `getTokenFromStore` provide abstraction for retrieving authentication data based on the **auth-key** UUID.
- Low-level KV operations reside in [`server/kv/cookie.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/kv/cookie.ts) using the `getMpCookie` and `setMpCookie` functions with the `cookie:` key prefix.

## Frequently Asked Questions

### How does the CookieStore handle cache eviction when memory is full?

When the in-memory Map exceeds the `maxSize` limit (default 1000), the `evictIfNeeded` method removes the oldest entry from the map's head. This LRU policy ensures that frequently accessed active sessions remain cached while stale entries are purged. The persistent KV storage retains the data until its four-day expiration, allowing reconstruction if the entry is requested again.

### What happens if the KV storage read fails or returns expired data?

If `getMpCookie` in [`server/kv/cookie.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/kv/cookie.ts) fails to find a key or the entry has expired, the function returns `null`. The calling code in `CookieStore.getAccountCookie` will then return `undefined`, effectively treating the session as non-existent. The API layer typically responds with a 401 status, forcing the client to re-authenticate and generate new cookies.

### Why use a two-layer approach instead of just KV storage?

The dual-layer architecture balances **performance** with **durability**. Reading from the in-memory Map provides sub-millisecond access times critical for high-throughput proxy requests, while the KV layer ensures session persistence across serverless cold starts. This design prevents the latency overhead of network calls to KV storage for every request while maintaining stateless server scalability.

### How is the auth-key generated and transmitted between client and server?

The **auth-key** is a UUID generated during the initial login flow. It is returned to the client and subsequently transmitted via the `X-Auth-Key` HTTP header or as an `auth-key` cookie. The `getCookieFromStore` and `getTokenFromStore` functions inspect both locations to identify the user session, enabling flexible authentication schemes across different client types.