Skip to main content

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-common cloud 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-common HTTP cloud function → WeChat sns/oauth2/access_token API
  • offiaccount-common returns { 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:

RoleResponsibility
Official Account webGuides the user to redirect to the WeChat authorization page; sends code to the backend after redirect
Cloud API gatewayValidates Bearer {accessToken}; forwards requests to the HTTP cloud function
offiaccount-common cloud functionHolds 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 platformIssues code, openid; delivers user profile
Integration CenterHosts AppID/AppSecret uniformly, injects them as env vars into the cloud function

Prerequisites

ItemRequirement
Official AccountService Account or a Subscription Account with snsapi_base enabled; WeChat-verified
Official Account AppID + AppSecretAvailable; AppSecret can be reset in Official Accounts platform → Basic Settings
Web authorization domainOfficial 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 environmentActivated; 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 platformTemplates & 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 as offiaccount-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-common does not use the _action field 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:

RoutePurposeRequired Body
POST /oauth/configReturns the appId of the Official Account configured in the current integration, so the frontend can compose the auth URL (avoiding hard-coding)
POST /oauth/tokenExchanges code for openid + OAuth access_token + refresh_token{ code }
POST /oauth/refreshRefreshes the OAuth access_token (uses the 30-day-valid refresh_token to get a new 2-hour token){ refresh_token }
POST /oauth/userinfoUses the OAuth access_token to fetch the authorized user's nickname/avatar (only valid with snsapi_userinfo scope){ access_token, openid }
POST /oauth/verifyValidates 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_token here and the Official Account's global access_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

scopeUXWhat you can get
snsapi_baseSilent, no popupOnly openid (used by most businesses)
snsapi_userinfoPops up an authorization confirmation pageopenid + 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 state parameter is required for CSRF protection (frontend generates a random string; verifies it after redirect)
  • accessToken must 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 (code can 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.

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.txt is 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

TopicLink
WeChat Web Authorization (official docs)https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
sns/oauth2/access_token API descriptionhttps://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#1
CloudBase Auth · Authenticated Loginhttps://docs.cloudbase.net/api-reference/webv2/authentication#%E8%AE%A4%E8%AF%81%E7%99%BB%E5%BD%95