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

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 (lines 18-22). This file stores the App ID, App Secret, and the official WeChat code2session endpoint URL.


# 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 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) 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).

# 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 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, 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.

# 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:

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:

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:

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, keeping secrets separate from business logic.
  • Service encapsulation: 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 and 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 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) 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 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 to route the request to verify_by_wx_mina rather than handling it as a standard username/password or mobile login.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →