# WeChat Mini Program Login Flow (code2Session) Implementation in Mini-Shop Server

> Learn how the Mini-Shop Server implements WeChat Mini Program login flow using code2session. Discover how we exchange codes for session keys, create user identities, and issue JWT tokens for secure authentication.

- Repository: [A粒麦子/mini-shop-server](https://github.com/allen7d/mini-shop-server)
- Tags: how-to-guide
- Published: 2026-02-24

---

**The Mini-Shop Server implements WeChat Mini Program authentication through a three-layer architecture that exchanges JavaScript login codes for session keys via the WeChat code2session API, creates user identities, and issues JWT tokens.**

The `allen7d/mini-shop-server` repository provides a complete Python-based backend for e-commerce applications, including robust support for WeChat Mini Program authentication. This server-side implementation handles the OAuth-style code2session flow, transforming temporary login codes from the Mini Program into persistent user sessions without exposing sensitive credentials to the client.

## Configuration and Credentials

### Secure Storage of WeChat App Settings

All WeChat Mini Program credentials are centralized in [`app/config/secure.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/config/secure.py) (lines 18-22). This file stores the **App ID**, **App Secret**, and the official WeChat `code2session` endpoint URL.

```python

# app/config/secure.py

WECHAT = {
    'APP_ID': 'wx551ff8259cd7339b',
    'APP_SECRET': '7773e41929841faf6aa9e68807f6e2cb',
    'LOGIN_URL': 'https://api.weixin.qq.com/sns/jscode2session'
}

```

Keeping these values in a dedicated secure module ensures that sensitive authentication parameters remain isolated from the main application configuration and can be easily rotated without affecting business logic.

## Token Service Layer

### Building the WeChat API Request

The [`app/service/wx_token.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/wx_token.py) file contains the **`WxToken`** class, which serves as the primary interface to the WeChat authentication servers. When instantiated, this class receives the JavaScript `code` obtained by the Mini Program via `wx.login`.

The class implements three key behaviors:

- **`wx_login_url` property** – Dynamically formats the complete request URL by interpolating `APP_ID`, `APP_SECRET`, and the provided `code` into the WeChat API template.
- **`get()` method** – Executes an HTTP GET request using the internal `HTTP` utility (from [`app/libs/httper.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/libs/httper.py)) to the formatted URL and parses the JSON response.
- **Error normalization** – Any `errcode` or `errmsg` returned by WeChat triggers a **`WeChatException`**, halting the authentication process immediately (lines 21-42).

```python

# app/service/wx_token.py (simplified logic)

class WxToken:
    def __init__(self, code):
        self.code = code
        self.app_id = current_app.config['WECHAT']['APP_ID']
        self.app_secret = current_app.config['WECHAT']['APP_SECRET']
        self.login_url = current_app.config['WECHAT']['LOGIN_URL']

    @property
    def wx_login_url(self):
        return f"{self.login_url}?appid={self.app_id}&secret={self.app_secret}&js_code={self.code}&grant_type=authorization_code"

    def get(self):
        result = HTTP.get(self.wx_login_url)
        if 'errcode' in result:
            raise WeChatException(msg=result['errmsg'])
        return result  # Contains openid, session_key, expires_in

```

## User Verification and Identity Management

### Client Type Routing

When the `/login` endpoint receives a request, [`app/service/login_verify.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/login_verify.py) inspects the `type` parameter to determine which authentication routine to execute. For WeChat Mini Programs, the client sends **`type=4`** (corresponding to `ClientTypeEnum.WX_MINA`), which triggers the **`verify_by_wx_mina`** method.

### Account Creation and Lookup Logic

The verification flow follows this exact sequence as implemented in the source code:

1. Instantiate `WxToken` with the provided `code`
2. Call `.get()` to exchange the code for WeChat's response containing `openid`
3. Query the **Identity** table for an existing record matching that `openid` and type `WX_MINA`
4. If no identity exists, invoke **`UserDao.register_by_wx_mina`** (defined in [`app/dao/user.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/dao/user.py), lines 68-77) to atomically create a new `User` record and a corresponding `Identity` entry linking the WeChat OpenID to the local user ID.
5. If an identity exists, fetch the associated `User` record by `user_id`.

```python

# app/service/login_verify.py (verify_by_wx_mina logic)

ut = WxToken(code)                  # ← receive the Mini-Program code

wx_result = ut.get()                # ← call WeChat code2session

openid = wx_result['openid']        # ← unique identifier

identity = Identity.get(identifier=openid,
                        type=ClientTypeEnum.WX_MINA.value)
if not identity:                     # first-time login → register

    user = UserDao.register_by_wx_mina(openid=openid)
else:
    user = User.get(id=identity.user_id)
return {'uid': user.id, 'scope': user.auth_scope}

```

After resolving the user record, the service generates a JWT-style authentication token via **`generate_auth_token`**, which the Mini Program stores for subsequent API requests.

## End-to-End Authentication Flow

The complete interaction between client, server, and WeChat follows this path:

```

Mini-Program (wx.login) → client sends `code` → POST /v1/login
   ↓
LoginVerifyService.verify_by_wx_mina (type=4)
   ↓
WxToken builds https://api.weixin.qq.com/sns/jscode2session?... & GETs it
   ↓
WeChat returns {openid, session_key, expires_in}
   ↓
Server looks up Identity → creates User via UserDao.register_by_wx_mina if needed
   ↓
generate_auth_token → token returned to Mini-Program

```

## Client Integration Examples

### Mini Program JavaScript Implementation

To initiate the flow from the client, call `wx.login` to obtain a temporary code, then POST it to the server with `type: 4`:

```javascript
wx.login({
  success(res) {
    if (res.code) {
      wx.request({
        url: 'https://your.api/v1/login',
        method: 'POST',
        data: { 
          account: res.code,  // The code from wx.login
          secret: '', 
          type: 4             // 4 == WX_MINA
        },
        success(r) {
          console.log('auth token:', r.data.token);
          wx.setStorageSync('token', r.data.token);
        }
      });
    }
  }
});

```

### Testing with cURL

For backend debugging or automated testing, simulate the Mini Program request:

```bash
curl -X POST https://your.api/v1/login \
  -H "Content-Type: application/json" \
  -d '{"account":"<CODE_FROM_WX_LOGIN>","secret":"","type":4}'

```

### Server-Side Debugging Script

To verify WeChat API connectivity independently of the application logic, reproduce the token exchange in Python:

```python
import requests

APP_ID = 'wx551ff8259cd7339b'
APP_SECRET = '7773e41929841faf6aa9e68807f6e2cb'
code = '<CODE_FROM_CLIENT>'

login_url = (
    f'https://api.weixin.qq.com/sns/jscode2session?'
    f'appid={APP_ID}&secret={APP_SECRET}&js_code={code}&grant_type=authorization_code'
)

result = requests.get(login_url).json()
print(result)   # {'openid': '...', 'session_key': '...', 'expires_in': 7200}

```

## Summary

- **Configuration isolation**: WeChat credentials live in [`app/config/secure.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/config/secure.py), keeping secrets separate from business logic.
- **Service encapsulation**: [`app/service/wx_token.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/wx_token.py) handles all direct communication with WeChat's `code2session` endpoint, normalizing errors into `WeChatException`.
- **Identity bridging**: [`app/service/login_verify.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/login_verify.py) and [`app/dao/user.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/dao/user.py) map WeChat OpenIDs to internal `User` records, automatically registering new users through `UserDao.register_by_wx_mina`.
- **Type dispatch**: The system uses `ClientTypeEnum.WX_MINA` (value `4`) to route Mini Program login requests to the appropriate verification handler.

## Frequently Asked Questions

### How does the server handle expired or invalid WeChat login codes?

The **`WxToken.get()`** method in [`app/service/wx_token.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/wx_token.py) inspects the JSON response from WeChat for `errcode` or `errmsg` fields. If present, it immediately raises a **`WeChatException`**, which propagates to the client as an authentication failure, preventing invalid codes from proceeding to the user lookup stage.

### What happens when a user logs in for the first time versus returning?

For first-time users, the `verify_by_wx_mina` function detects that no `Identity` record exists for the provided `openid` and `type=WX_MINA`. It then calls **`UserDao.register_by_wx_mina`** (lines 68-77 in [`app/dao/user.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/dao/user.py)) to create both a new `User` entity and a linked `Identity` entry. Returning users simply have their existing record fetched by `Identity.get`, bypassing the registration logic.

### Is the session_key returned by WeChat stored or used by the server?

While the WeChat API returns `session_key`, `openid`, and `expires_in`, the current implementation in [`app/service/login_verify.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/login_verify.py) primarily utilizes the **`openid`** as the unique user identifier. The `session_key` is available in the raw response from `WxToken.get()` but is not persisted in the provided code snippets, suggesting the server relies on its own JWT token mechanism rather than WeChat's session key for ongoing session management.

### How does the client specify it wants WeChat Mini Program authentication?

The client must send **`type: 4`** in the JSON payload to the `/v1/login` endpoint, which corresponds to `ClientTypeEnum.WX_MINA.value`. This numeric discriminator allows `LoginVerifyService` in [`app/service/login_verify.py`](https://github.com/allen7d/mini-shop-server/blob/main/app/service/login_verify.py) to route the request to `verify_by_wx_mina` rather than handling it as a standard username/password or mobile login.