# WeChat QR Code Scan Login Flow: How scan.get.ts Handles Authentication Polling in wechat-article-exporter

> Explore how scan.get.ts in wechat-article-exporter handles WeChat QR code scan login authentication polling by proxying client UUID to WeChat's backend for confirmation.

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

---

**The [`scan.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/scan.get.ts) endpoint serves as a stateless polling proxy that forwards the client's `uuid` cookie to WeChat's MP backend, checking whether a QR code has been scanned and confirmed to trigger the final authentication step.**

The wechat-article-exporter project implements a server-side QR code authentication system to access WeChat MP (Official Accounts Platform) data without exposing sensitive credentials to the browser. At the heart of this flow lies the [`server/api/web/login/scan.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/api/web/login/scan.get.ts) handler, which continuously queries WeChat's API to track scan status while maintaining secure session state server-side.

## Role of scan.get.ts in the Three-Step QR Code Login Flow

The authentication sequence follows a strict orchestration between three Nuxt server endpoints:

1. **[`getqrcode.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/getqrcode.get.ts)** – Initializes the session by requesting a fresh QR code from WeChat and setting a `uuid` cookie to identify the login attempt.
2. **[`scan.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/scan.get.ts)** – Polls the WeChat backend using the stored `uuid` to detect when the user scans the code and confirms the login.
3. **`session/[sid].post.ts`** – Completes the handshake by exchanging the confirmed session ID for an authentication token, storing credentials server-side in the **CookieStore**, and issuing an `auth-key` cookie to the client.

Within this pipeline, [`scan.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/scan.get.ts) functions as the critical bridge between QR code generation and final credential exchange.

### Forwarding Poll Requests to WeChat

Located at [`server/api/web/login/scan.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/api/web/login/scan.get.ts), the handler extracts all cookies from the incoming request—specifically the `uuid` set during initialization—and proxies them to WeChat's scan status endpoint:

```typescript
// server/api/web/login/scan.get.ts
import { getCookiesFromRequest } from '~/server/utils/CookieStore';
import { proxyMpRequest } from '~/server/utils/proxy-request';

export default defineEventHandler(async event => {
  // Extract the uuid cookie identifying this login session
  const cookie = getCookiesFromRequest(event);

  // Forward GET request to WeChat's scan status endpoint
  return proxyMpRequest({
    event,
    method: 'GET',
    endpoint: 'https://mp.weixin.qq.com/cgi-bin/scanloginqrcode',
    query: {
      action: 'ask',
      token: '',
      lang: 'zh_CN',
      f: 'json',
      ajax: 1,
    },
    cookie, // Passes uuid to correlate with the QR code
  });
});

```

The `getCookiesFromRequest` utility aggregates all client-sent cookies into a formatted `Cookie` header, while `proxyMpRequest` (defined in [`server/utils/proxy-request.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/utils/proxy-request.ts)) transparently forwards the request to WeChat without modifying the response body.

## Interpreting WeChat's Scan Status Responses

The endpoint returns raw JSON from WeChat's `cgi-bin/scanloginqrcode` API, which contains a `status` field indicating the authentication progress:

- **`0`** – QR code generated but not yet scanned (pending)
- **`1`** – User has scanned the code but not confirmed the login
- **`2`** – User confirmed the login; ready to proceed to credential exchange

The client implements a polling loop—typically every 2 seconds—calling [`scan.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/scan.get.ts) until receiving `status: 2`, at which point it proceeds to the `session/[sid].post.ts` endpoint to finalize authentication.

## Integration with Server-Side CookieStore

While [`scan.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/scan.get.ts) itself is stateless, it relies on the **CookieStore** system ([`server/utils/CookieStore.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/utils/CookieStore.ts)) to maintain session continuity. The `uuid` cookie passed through this endpoint links the polling request to the specific QR code session created in step 1. 

After the scan confirms (`status: 2`), the subsequent `session/[sid].post.ts` handler:

1. Posts to `https://mp.weixin.qq.com/cgi-bin/bizlogin?action=startlogin`
2. Extracts the authentication token from the redirect URL
3. Stores the token and all Set-Cookie headers in the server-side **CookieStore** via `cookieStore.setCookie`
4. Returns an `auth-key` cookie to the client for subsequent API requests

This architecture ensures WeChat credentials never reach the browser, maintaining security while enabling automated content export.

## Client-Side Polling Implementation

Frontend applications consume this endpoint through a simple polling pattern:

```javascript
// Request QR code and store uuid cookie
const { qrcode_url } = await $fetch('/api/web/login/getqrcode');

// Poll until user confirms
async function waitForScan() {
  while (true) {
    const response = await $fetch('/api/web/login/scan');
    // Response: { status: 0, message: "waiting" } or { status: 2, ... }
    
    if (response.status === 2) break; // Confirmed, exit loop
    await new Promise(r => setTimeout(r, 2000)); // Wait 2 seconds
  }
  
  // Complete login with session ID obtained from previous step
  await $fetch(`/api/web/login/session/${sid}`, { method: 'POST' });
  // Server now sets auth-key cookie for authenticated requests
}

```

The [`scan.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/scan.get.ts) endpoint handles the complexity of WeChat's authentication protocol while presenting a clean JSON interface to the frontend.

## Summary

- **[`scan.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/scan.get.ts)** acts as a transparent proxy between the client and WeChat's `cgi-bin/scanloginqrcode` endpoint, enabling secure status polling without exposing WeChat credentials.
- The endpoint requires the `uuid` cookie set by [`getqrcode.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/getqrcode.get.ts) to correlate polling requests with specific QR code sessions.
- **Status codes** (`0`, `1`, `2`) indicate pending, scanned, and confirmed states respectively, driving the client-side polling logic.
- Upon confirmation (`status: 2`), control passes to `session/[sid].post.ts` to finalize authentication and populate the server-side **CookieStore**.
- This implementation keeps sensitive WeChat session data server-side while allowing the client to track login progress through simple JSON polling.

## Frequently Asked Questions

### What is the purpose of the scan.get.ts endpoint in wechat-article-exporter?

The [`scan.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/scan.get.ts) endpoint polls WeChat's MP backend to check whether a user has scanned and confirmed a QR code login. It forwards the client's `uuid` cookie to WeChat's `scanloginqrcode` API and returns the raw status response, allowing the frontend to determine when to proceed to the final authentication step.

### How does scan.get.ts know which QR code session to check?

The endpoint retrieves the `uuid` cookie (set during the initial [`getqrcode.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/getqrcode.get.ts) call) from the incoming request using `getCookiesFromRequest`. This cookie is passed directly to WeChat's API via `proxyMpRequest`, enabling WeChat to match the polling request with the correct pending login session.

### What do the status codes returned by scan.get.ts mean?

WeChat's API returns three primary status values in the JSON response: `0` indicates the QR code is waiting to be scanned, `1` means the user has scanned but not yet confirmed the login, and `2` signifies the user has confirmed and the session is ready for credential exchange via `session/[sid].post.ts`.

### Why does the server proxy the request instead of calling WeChat directly from the browser?

Direct browser requests to WeChat would expose sensitive cookies and authentication tokens to the client, creating security vulnerabilities. By proxying through [`scan.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/scan.get.ts), the server maintains control over session state using the **CookieStore** utility, ensuring WeChat credentials remain server-side while the client only handles session identifiers like `uuid` and `auth-key`.