Official Account Integration Guide · Web Authorization
After creating a "WeChat Official Account" integration in the CloudBase console, the system automatically generates an HTTP cloud function (function name like <integration-id>-<random-string>, hereinafter referred to as offiaccount-common). This guide only covers Web Authorization (OAuth 2.0) — the most commonly used and highest-frequency capability of the Official Account integration, used in Official Account scenarios to let web pages obtain a user's openid and (optionally) nickname/avatar.
Other capabilities (access_token hosting, JS-SDK, template/subscribe messages, customer service messages, menu, QR code, user management, materials, etc.) are provided by the same
offiaccount-commoncloud function and are not covered in this guide.
End-to-end pipeline:
- Web redirect → WeChat authorization page → WeChat redirects back with
code - Web carries
code→ CloudBase cloud API gateway (accessToken auth) →offiaccount-commonHTTP cloud function → WeChatsns/oauth2/access_tokenAPI offiaccount-commonreturns{ openid, access_token, ... }to the web or business backend
Architecture Overview
┌──────────────────┐
│ Off. Acc. Web │
│ (WeChat browser)│
└────────┬─────────┘
│ 1. Redirect to open.weixin.qq.com/connect/oauth2/authorize
│ ?appid=...&redirect_uri=...&scope=snsapi_base&state=...
▼
┌──────────────────┐
│ WeChat auth pg │ User authorizes / snsapi_base silent
└────────┬─────────┘
│ 2. Redirect to redirect_uri with ?code=xxx&state=xxx
▼
┌──────────────────┐
│ Off. Acc. Web │
└────────┬─────────┘
│ 3. POST { code } to /oauth/token, with Bearer accessToken
▼
┌──────────────────────────┐
│ CloudBase Cloud API GW │ accessToken auth
└────────┬─────────── ──────┘
│ HTTP invoke
▼
┌────────────────────────────┐
│ offiaccount-common │
│ POST /oauth/token │
│ → calls sns/oauth2/... │
│ ← returns openid + tokens │
└────────────────────────────┘
Responsibility breakdown:
| Role | Responsibility |
|---|---|
| Official Account web | Guides the user to redirect to the WeChat authorization page; sends code to the backend after redirect |
| Cloud API gateway | Validates Bearer {accessToken}; forwards requests to the HTTP cloud function |
offiaccount-common cloud function | Holds AppID + AppSecret; uses code to call WeChat to exchange openid and OAuth tokens; calls sns/userinfo on demand to fetch user profile |
| WeChat Official Accounts platform | Issues code, openid; delivers user profile |
| Integration Center | Hosts AppID/AppSecret uniformly, injects them as env vars into the cloud function |
Prerequisites
| Item | Requirement |
|---|---|
| Official Account | Service Account or a Subscription Account with snsapi_base enabled; WeChat-verified |
| Official Account AppID + AppSecret | Available; AppSecret can be reset in Official Accounts platform → Basic Settings |
| Web authorization domain | Official Accounts platform → Settings & Development → Official Account Settings → Functional Settings → Web Authorization Domain; the page domain that initiates authorization is added and MP_verify_xxx.txt verification has been completed |
| CloudBase environment | Activated; at least one authenticated login method available (anonymous login cannot call cloud functions, see section 4.3) |
Step 1 · Prepare Official Account Credentials
Log in to the WeChat Official Accounts platform → Settings & Development → Basic Settings:
- AppID: like
wxc1546068399a59fc - AppSecret: click "Reset" to generate; shown only once, keep it safe
Do not leak the AppSecret to the frontend. The CloudBase Integration Center hosts it and injects it into the cloud function env vars.
Step 2 · Create the Integration in CloudBase
2.1 Enter Integration Center
Path: CloudBase platform → Templates & Integrations → Integration Center → WeChat Official Account → Create Integration.
2.2 Fill in Integration Information
The console wizard requires:
- Integration name (custom, e.g.
offiaccount-demo) - Official Account AppID and AppSecret
Integration Center will host the credentials above in a unified manner.
2.3 Auto-generated Cloud Function Resources
Upon successful creation, the system automatically performs two operations:
- Creates an HTTP cloud function based on the integration name (function name like
<integration-id>-<random-string>, hereinafter referred to asoffiaccount-common). - Injects the AppID and AppSecret as environment variables into that cloud function.
Step 3 · Understand the offiaccount-common Cloud Function
When the integration was created in Step 2, the platform has already injected the AppID and AppSecret as environment variables into the cloud function. They are read at runtime via process.env; no plaintext credentials appear in the business code.
To modify configuration, go to "Integration Center → corresponding integration → Edit"; after saving, the platform automatically redeploys the cloud function.
3.1 Web Authorization Routes
⚠️ Unlike the "WeChat Pay" integration's pay-common,
offiaccount-commondoes not use the_actionfield for dispatch, but uses REST paths directly. When calling the cloud function, use the full path, e.g.POST /oauth/token.
The 5 REST routes for web authorization exposed by the cloud function:
| Route | Purpose | Required Body |
|---|---|---|
POST /oauth/config | Returns the appId of the Official Account configured in the current integration, so the frontend can compose the auth URL (avoiding hard-coding) | — |
POST /oauth/token | Exchanges code for openid + OAuth access_token + refresh_token | { code } |
POST /oauth/refresh | Refreshes the OAuth access_token (uses the 30-day-valid refresh_token to get a new 2-hour token) | { refresh_token } |
POST /oauth/userinfo | Uses the OAuth access_token to fetch the authorized user's nickname/avatar (only valid with snsapi_userinfo scope) | { access_token, openid } |
POST /oauth/verify | Validates whether the OAuth access_token is still valid | { access_token, openid } |
All routes uniformly return { code: 0, msg: 'success', data: <business-data> }; on errors return { code: -1, msg, data: null }.
The OAuth
access_tokenhere and the Official Account's globalaccess_token(used for menu/messaging APIs) are two different things; the former can only be used to fetch the current user's profile and cannot call other APIs.
3.2 Pipeline and Authentication
The pipeline for calling offiaccount-common is identical to pay-common:
The frontend logs in to CloudBase to get an accessToken → carries Authorization: Bearer {accessToken} to request the cloud API gateway → the gateway dispatches to offiaccount-common.
The accessToken must come from "authenticated login" — anonymous login tokens have no permission to call cloud functions; the gateway will return 401. For login methods (email, phone, custom login, etc.), see CloudBase Web SDK · Authenticated Login.
Step 4 · Integrate Web Authorization
4.1 Prerequisites
Configure the web authorization domain
Path: WeChat Official Accounts platform → Settings & Development → Official Account Settings → Functional Settings → Web Authorization Domain.
Download MP_verify_xxx.txt, place it at a location accessible at https://<your-domain>/MP_verify_xxx.txt, then click verify.
The domain must be the domain of the page that initiates authorization, not the domain of the redirect-handling page (although they are usually the same).
Understand the two scopes
| scope | UX | What you can get |
|---|---|---|
snsapi_base | Silent, no popup | Only openid (used by most businesses) |
snsapi_userinfo | Pops up an authorization confirmation page | openid + nickname + avatar + gender, etc. |
4.2 Complete Web Authorization Flow
A four-step flow; the first two steps are done in the frontend, step 3 goes through offiaccount-common, and step 4 is called as needed.
Step 1: Web → redirect to WeChat auth page
Step 2: WeChat → redirect to frontend redirect_uri with ?code=xxx
Step 3: Frontend → POST /oauth/token { code } → get openid + access_token
Step 4: Frontend → POST /oauth/userinfo (only needed for snsapi_userinfo)
4.3 Complete Invocation Example
Suitable for Official Account H5 pages opened in the WeChat built-in browser.
Key constraints:
- The page must be opened in the WeChat built-in browser; opening the WeChat auth page in external browsers (Chrome / Safari) will redirect to a hint page
- The page URL domain must already be in the Official Account's "Web Authorization Domain" allowlist
- The
stateparameter is required for CSRF protection (frontend generates a random string; verifies it after redirect) accessTokenmust come from authenticated login; see 3.2
<!-- oauth.html authorization initiation page -->
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>Authorizing…</title></head>
<body>
<script src="https://cdn.jsdelivr.net/npm/@cloudbase/js-sdk/dist/cloudbase.full.js"></script>
<script>
const ENV_ID = 'your-env-id'
const FN_NAME = 'offiaccount-common' // actual function name generated after integration creation
const app = cloudbase.init({ env: ENV_ID })
const auth = app.auth({ persistence: 'local' })
// ⚠️ accessToken must come from "authenticated login"; anonymous login has no permission to call cloud functions
// For full login methods, see https://docs.cloudbase.net/api-reference/webv2/authentication#%E8%AE%A4%E8%AF%81%E7%99%BB%E5%BD%95
async function getAccessToken() {
// Example placeholder: business side must implement real login and return accessToken
throw new Error('Implement authenticated login per CloudBase Web SDK docs and return accessToken')
}
async function callFn(token, path, body) {
const res = await fetch(
`https://${ENV_ID}.api.tcloudbasegateway.com/v1/functions/${FN_NAME}${path}?webfn=true`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(body || {}),
}
)
return res.json()
}
function unwrap(body) {
// offiaccount-common returns { code, msg, data } directly; no extra wechatpay-node-v3 wrap layer
return body && body.code === 0 ? body.data : null
}
;(async () => {
const token = await getAccessToken()
const url = new URL(location.href)
const code = url.searchParams.get('code')
const state = url.searchParams.get('state')
// —— Step 1: no code, initiate authorization ——
if (!code) {
// Get AppID (you can also hard-code it in the frontend)
const { appId } = unwrap(await callFn(token, '/oauth/config')) || {}
if (!appId) { alert('appId not retrieved'); return }
const randomState = Math.random().toString(36).slice(2, 18)
sessionStorage.setItem('oauth_state', randomState)
// Use the current page as redirect_uri; re-enters this script after redirect
const redirectUri = encodeURIComponent(location.href.split('?')[0])
location.replace(
`https://open.weixin.qq.com/connect/oauth2/authorize` +
`?appid=${appId}` +
`&redirect_uri=${redirectUri}` +
`&response_type=code` +
`&scope=snsapi_base` + // change to snsapi_userinfo to fetch nickname/avatar
`&state=${randomState}` +
`#wechat_redirect`
)
return
}
// —— Step 2: redirect brought back code; verify state ——
const expectedState = sessionStorage.getItem('oauth_state')
if (state !== expectedState) {
alert('state verification failed; suspected CSRF')
return
}
sessionStorage.removeItem('oauth_state')
// —— Step 3: exchange code for openid ——
const tokenRes = unwrap(await callFn(token, '/oauth/token', { code }))
if (!tokenRes || !tokenRes.openid) {
alert('Failed to exchange openid')
return
}
const { openid, access_token, refresh_token, scope } = tokenRes
console.log('Got openid:', openid, 'scope:', scope)
// —— Step 4 (optional): only snsapi_userinfo can fetch profile ——
if (scope === 'snsapi_userinfo') {
const info = unwrap(await callFn(token, '/oauth/userinfo', {
access_token,
openid,
}))
console.log('User profile:', info) // { nickname, headimgurl, sex, ... }
}
// Business side: write openid to session / redirect to business page
sessionStorage.setItem('openid', openid)
location.replace('/home')
})()
</script>
</body>
</html>
4.4 Calling /oauth/refresh and /oauth/verify
The OAuth access_token expires after 2 hours by default. To reuse openid-associated profile-fetching capabilities in long-session scenarios:
// Refresh: use refresh_token to exchange for a new access_token (refresh_token valid for 30 days)
const refreshed = unwrap(await callFn(token, '/oauth/refresh', {
refresh_token,
}))
// refreshed = { openid, access_token, refresh_token, expires_in, scope }
// Verify: judge whether the token is still valid
const { valid } = unwrap(await callFn(token, '/oauth/verify', {
access_token,
openid,
}))
Most businesses do not need to persist OAuth access_token — once you have openid, you can store it to associate with a user; other Official Account capabilities (messages/customer service etc.) use the global access_token (hosted by offiaccount-common's /token/* routes).
FAQ
Q1: Calling /oauth/token returns "WeChat API error [40029]: invalid code"
There are three cases that yield this error for code:
- It has been used once (
codecan only be consumed once; the frontend mistakenly called it twice, or the page was refreshed with code and redirected again) - It has expired (valid within 5 minutes)
- It does not match the AppID used at authorization initiation (e.g. integration uses A but the auth URL uses B)
Troubleshoot: clear cache and retry; ensure the frontend doesn't re-enter.
Q2: Calling /oauth/token returns "invalid appsecret" or 40125
The AppSecret filled in Integration Center is wrong, or has been reset on the Official Accounts platform. Go to Integration Center → Edit → re-paste the AppSecret.
Q3: Auth page shows "This link cannot be accessed, please check whether the link is correct" / "redirect_uri domain does not match backend configuration"
The redirect_uri domain is not in the Official Accounts platform's "Web Authorization Domain" allowlist. Check:
- Whether the domain matches exactly (including subdomain; the Official Accounts platform only allows filling in the main domain, subdomains are auto-covered)
- Whether the verification file
MP_verify_xxx.txtis actually accessible - Wait 1–2 minutes after configuration to take effect
Q4: snsapi_base does not return nickname/avatar
This is by design. snsapi_base only returns openid; to fetch profile, you must use snsapi_userinfo, which pops up a user confirmation dialog.
Q5: Can the page run in WeWork or QQ Browser?
No. open.weixin.qq.com/connect/oauth2/authorize only works in the WeChat built-in browser; external browsers will redirect to a hint page.
Q6: Can I call https://api.weixin.qq.com/sns/oauth2/access_token directly from the frontend?
You cannot, and you should not. That API mandatorily requires AppSecret; calling it from the frontend exposes the AppSecret, and WeChat also validates the source IP. This is exactly why offiaccount-common exists — to keep AppSecret on the server.
Q7: Can I reuse the same CloudBase environment as pay-common?
Yes. offiaccount-common and pay-common are two independent integrations, each generating its own HTTP cloud function; they don't affect each other. The frontend calls each as needed.
Further Reading
| Topic | Link |
|---|---|
| WeChat Web Authorization (official docs) | https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html |
sns/oauth2/access_token API description | https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#1 |
| CloudBase Auth · Authenticated Login | https://docs.cloudbase.net/api-reference/webv2/authentication#%E8%AE%A4%E8%AF%81%E7%99%BB%E5%BD%95 |