WeChat QR Code Login Configuration Guide
WeChat Official Account QR Code Login Configuration and Integration
Prerequisites · Environment Variables · WeChat Backend Configuration · API Endpoints
🎯 Overview
This document explains how to configure WeChat Official Account QR code login functionality. The WeChat login is implemented through the Better Auth plugin mechanism, supporting user creation, account binding, unbinding, and other complete features.
Changelog
- v1.1.0 (2025-12)
- Use
setSessionCookieinstead of manually setting cookies, following better-auth standards - Add complete OpenAPI metadata for API documentation generation
- Add hooks for post-login logic handling
- Use
mergeSchemafor optimized schema extension - Add
unbindWechatunbinding endpoint - Support
onUserCreatedandonSignIncallback functions
- Use
📋 Prerequisites
Before starting configuration, ensure the following conditions are met:
| Condition | Description |
|---|---|
| Verified WeChat Service Account | Subscription accounts do not support parametric QR codes |
| Publicly accessible server | For receiving WeChat message callbacks |
Subscription accounts cannot use parametric QR code functionality. A verified Service Account is required.
🔧 Environment Variables
Add the following configuration to your .env or .env.local file:
# ==========================================
# WeChat Official Account Configuration (WeChat QR Login)
# ==========================================
# Official Account AppID (found in Official Account Backend > Settings & Development > Basic Configuration)
WECHAT_MP_APPID=wx1234567890abcdef
# Official Account AppSecret (found in Official Account Backend > Settings & Development > Basic Configuration)
WECHAT_MP_SECRET=your_app_secret_here
# Server Configuration Token (custom, for WeChat server verification)
# Recommended: use a random string, e.g.: openssl rand -hex 16
WECHAT_MP_TOKEN=your_custom_token_here
# Message Encryption Key (optional, if using secure mode)
# WECHAT_MP_ENCODING_AES_KEY=your_encoding_aes_key_here📱 WeChat Developer Platform Configuration
Since 2025, WeChat has migrated the "Development Interface Management" module for Official Accounts/Service Accounts to the WeChat Developer Platform. For details, see the official migration guide.
1. Obtain AppID and AppSecret
- Log in to WeChat Developer Platform (scan with WeChat)
- Navigate to My Business > Official Account/Service Account > Basic Info
- Record the Developer ID (AppID)
- In Basic Info > Development Key, enable and obtain the AppSecret
AppSecret is not stored or displayed on the platform. Please save it securely after enabling. If forgotten, you'll need to use the "Reset" function to regenerate it.
2. Configure Server (Message Push)
- Navigate to My Business > Official Account/Service Account > Basic Info > Domain & Message Push Configuration
- In "Message Push", click Modify Configuration
- Fill in the following information:
- URL:
https://your-domain.com/api/v1/pub/mp/webhook - Token: Must match the
WECHAT_MP_TOKENenvironment variable - EncodingAESKey: Click to randomly generate (optional)
- Message Encryption Method: Choose Plain Text Mode (recommended for development) or Secure Mode
- URL:
- Click Submit
3. Enable Service
- Ensure server configuration verification passes
- Click the Enable button
4. Configure API IP Whitelist
- Navigate to My Business > Official Account/Service Account > Basic Info > Development Key
- Add your server's public IP address in API IP Whitelist
When calling Official Account/Service Account APIs, the request IP must be added to the API IP Whitelist, otherwise the API call will return error code 40164.
🛠️ Development Environment Debugging
Using ngrok for Tunneling
Since WeChat servers need to access a public address, you'll need to use a tunneling tool for local development:
# Install ngrok
npm install -g ngrok
# Start tunnel (assuming local server runs on port 3000)
ngrok http 3000Then use the HTTPS address provided by ngrok to configure the WeChat backend.
Debug Logs
Detailed logging has been added to the API routes. View them in the console:
| Log Prefix | Description |
|---|---|
[WeChat MP] * | Official Account utility library logs |
[WeChat Webhook] * | Message callback logs |
[API] * | API route logs |
📡 API Endpoints
1. Get Login QR Code
GET /api/v1/pub/mp/get-qrcodeResponse Example:
{
"success": true,
"data": {
"sceneId": "login_1702800000000_abc123",
"qrcodeUrl": "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=xxx",
"expiresIn": 300
}
}2. Poll Scan Result
GET /api/v1/pub/mp/get-scan-result?sceneId=login_xxxResponse Example (Not Scanned):
{
"success": true,
"data": {
"scanned": false
}
}Response Example (Scanned):
{
"success": true,
"data": {
"scanned": true,
"unionid": "o6xxx...",
"openid": "oGxxx...",
"nickname": "Username",
"avatar": "https://..."
}
}3. WeChat Message Callback
GET /api/v1/pub/mp/webhook - Server verification
POST /api/v1/pub/mp/webhook - Message/event reception🔄 Login Flow
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Browser │ │ Server │ │WeChat Server│ │ User Phone │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │ │
│ 1. Request QR │ │ │
│───────────────────>│ │ │
│ │ 2. Create temp QR │ │
│ │───────────────────>│ │
│ │<───────────────────│ │
│ 3. Return QR URL │ │ │
│<───────────────────│ │ │
│ │ │ │
│ 4. Poll scan │ │ │
│───────────────────>│ │ │
│ (every 2s) │ │ │
│ │ │ 5. User scans │
│ │ │<───────────────────│
│ │ 6. Push scan event│ │
│ │<───────────────────│ │
│ │ 7. Get user info │ │
│ │───────────────────>│ │
│ │<───────────────────│ │
│ 8. Return success │ │ │
│<───────────────────│ │ │
│ │ │ │
│ 9. Call login API │ │ │
│───────────────────>│ │ │
│ 10. Create session│ │ │
│<───────────────────│ │ │
│ │ │ │
│ 11. Redirect │ │ │
│ │ │ │⚙️ Plugin Configuration Options
wechatPlugin supports the following configuration options:
import { wechatPlugin } from '@/lib/auth/plugins/wechat';
wechatPlugin({
// Temporary email domain (for WeChat user placeholder emails)
emailDomainName: 'your-domain.com', // Default: 'wechat.placeholder'
// Custom schema extension
schema: {
account: {
fields: {
// Custom fields...
},
},
},
// Callback after user creation
onUserCreated: async ({ user, unionid, openid, ctx }) => {
console.log('New user created:', user.id);
// Send welcome message, initialize user data, etc.
},
// Callback after successful sign-in
onSignIn: async ({ user, session, isNewUser, ctx }) => {
console.log('User signed in:', user.id, 'isNew:', isNewUser);
// Record login log, send notifications, etc.
},
});💻 Client API
The client plugin provides the following methods:
import { authClient } from '@/lib/auth/auth-client';
// WeChat QR code login
const result = await authClient.signInWechat({
unionid: 'xxx',
openid: 'xxx',
nickname: 'Username', // Optional
avatar: 'https://...', // Optional
});
// Check if WeChat is already bound
const { bound } = await authClient.checkWechatBinding({
unionid: 'xxx',
});
// Bind WeChat to current account (requires login)
const bindResult = await authClient.bindWechat({
unionid: 'xxx',
openid: 'xxx',
});
// Unbind WeChat from current account (requires login)
const unbindResult = await authClient.unbindWechat();👥 User Management and Account Association
Admin Backend User Management
After users log in via WeChat QR code, administrators can perform the following operations in the backend:
1. Set Username
WeChat login users don't have a username by default. Administrators can set usernames for users in the backend:
- Location: Admin Backend > User Management > Edit User
- Description: After setting a username, users can log in using
username + password - Notes: Usernames must be unique
2. Reset Password
Set a password for WeChat login users, allowing them to use account/password login:
- Location: Admin Backend > User Management > Reset Password
- Use Cases: User forgets WeChat account or wants to use traditional account/password login
3. User Information Management
Administrators can view and manage WeChat login user information:
- View User Info: Including user ID, email (placeholder email), creation time, last login time, etc.
- View Login Methods: WeChat binding information can be seen in the account association list
- Edit User Profile: Modify username, avatar, and other basic information
Multiple Login Methods Support
After completing WeChat QR code login, the system supports the following login methods:
Method 1: WeChat QR Code Login
- Click "WeChat Login" button
- Scan the QR code
- Follow the official account (first time) or scan directly
- Auto login successful
Method 2: Account/Password Login
After the administrator sets username and password for the user, they can use:
- Username + Password: Login with administrator-set username and password
- Email + Password: Login with placeholder email (format:
{openid}@wechat.placeholder) and password
WeChat login users' emails are placeholder emails, mainly used for internal system identification. It's recommended that administrators set usernames for users - username login is more user-friendly.
Account Binding and Unbinding
Check if WeChat is Bound
const { bound } = await authClient.checkWechatBinding({
unionid: 'xxx',
});Bind WeChat to Current Account
// Requires user to be logged in (has session)
const result = await authClient.bindWechat({
unionid: 'xxx',
openid: 'xxx',
});Unbind WeChat
// Requires user to be logged in
const result = await authClient.unbindWechat();Binding Scenario Examples
Scenario 1: User has existing email account, wants to bind WeChat
// 1. User logs in with email/password
await authClient.signIn.email({
email: '[email protected]',
password: 'password',
});
// 2. User scans and gets unionid/openid
const { unionid, openid } = getWechatUserInfo();
// 3. Check if WeChat is already bound
const { bound } = await authClient.checkWechatBinding({ unionid });
if (!bound) {
// 4. Bind WeChat to current account
await authClient.bindWechat({ unionid, openid });
}Scenario 2: User logs in with WeChat first, then binds email
// 1. User logs in with WeChat QR code
await authClient.signInWechat({ unionid, openid });
// 2. User sets email and password
await authClient.changeEmail({
newEmail: '[email protected]',
});
await authClient.changePassword({
currentPassword: '',
newPassword: 'newPassword',
});❓ FAQ
Q: QR code generation fails with "WeChat API Error"
Check the following configurations:
- Are
WECHAT_MP_APPIDandWECHAT_MP_SECRETcorrect? - Is the server IP added to the whitelist?
- Is the official account verified (subscription accounts don't support parametric QR codes)?
Q: Server configuration verification fails
Check the following configurations:
- Is the URL publicly accessible (HTTPS)?
- Does the Token match the environment variable?
- Check server logs for verification requests
Q: No event received after scanning
Check the following configurations:
- Is server configuration enabled?
- Is the correct verified service account being used?
- Check webhook logs for POST requests
Q: Cannot get unionid
One of the following conditions must be met:
- User has followed the official account
- Official account is bound to WeChat Open Platform
It's recommended to bind the official account to WeChat Open Platform to obtain unionid for cross-application user unification.
Q: Why can't I get user's nickname and avatar?
Important Note: Since December 27, 2021, WeChat has adjusted the interface policy:
- When obtaining user information through backend interface (global
access_token), nickname and avatar are no longer returned - These information can only be obtained when users authorize through web authorization (OAuth2.0) and explicitly agree
Current Implementation:
- In the QR code login flow, we can only get
openidandunionid - Cannot obtain user's nickname and avatar through backend interface
- This is a WeChat official restriction, not a code issue
Solutions:
- Accept the status quo: Use
openid/unionidfor login, leave nickname and avatar empty or use default values - Use web authorization: Guide users through the web authorization flow to get user information (adds user operation steps)
🔒 Security Recommendations
- Protect AppSecret: Don't commit AppSecret to code repositories
- Use Secure Mode: Enable message encryption in production
- Verify Signatures: All WeChat requests have signature verification to ensure trusted sources
- Limit API Access: Consider adding rate limiting to prevent abuse
✨ Best Practice Recommendations
-
New User Flow:
- User scans WeChat QR code → Auto create account → Admin sets username and password → User can choose any login method
-
Account Security:
- Set strong passwords for WeChat login users
- Regularly check account associations
- Promptly handle abnormal login behaviors
-
User Experience:
- Guide users to complete their profile after first login (set username, email, etc.)
- Provide multiple login methods to enhance user experience
- Display bound login methods in user settings
-
Data Consistency:
- Ensure users can access the same account data regardless of login method
- Account association information is stored uniformly in the
accounttable
📁 Related Files
| File Path | Description |
|---|---|
lib/auth/plugins/wechat/index.js | Better Auth server plugin |
lib/auth/plugins/wechat/client.js | Better Auth client plugin |
lib/wechat/mp.js | WeChat Official Account API utility library |
app/api/v1/pub/mp/get-qrcode/route.js | Get QR code API |
app/api/v1/pub/mp/get-scan-result/route.js | Get scan result API |
app/api/v1/pub/mp/webhook/route.js | WeChat message callback API |
components/auth/wechat-login-dialog.js | WeChat login dialog component |