yikart/AiToEarn · error · AppException
ChannelAuthRefreshTokenMissing
ChannelAuthRefreshTokenMissing
Error message
ChannelAuthRefreshTokenMissing
What it means
The WeChat Official Account auth provider refreshes access tokens via the stored refresh token. Because WeChat OAuth refresh requires a refresh_token, calling refresh without one throws AppException(ResponseCode.ChannelAuthRefreshTokenMissing).
Source
Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/wechat/wechat-official/wechat-official-auth.provider.ts:68
const callback = parseOAuthCallback(input)
const result = await this.wechatService.exchangeOfficialCode(callback.code)
return {
accessToken: result.accessToken,
refreshToken: result.refreshToken,
expiresAt: new Date(Date.now() + result.expiresIn * 1000),
scope: result.scope,
platformUid: result.openId,
raw: {
openId: result.openId,
unionId: result.unionId,
},
}
}
async refresh(input: RefreshCredentialInput): Promise<CredentialResult> {
if (!input.refreshToken) {
throw new AppException(ResponseCode.ChannelAuthRefreshTokenMissing)
}
const result = await this.wechatService.refreshOfficialToken(input.refreshToken)
return {
accessToken: result.accessToken,
refreshToken: result.refreshToken,
expiresAt: new Date(Date.now() + result.expiresIn * 1000),
scope: result.scope,
}
}
async revoke(_input: RevokeCredentialInput): Promise<void> {
// WeChat Official Account OAuth does not support server-side token revocation.
// Tokens expire naturally (2 hours for access, 30 days for refresh).
this.logger.log('WeChat Official Account tokens expire naturally; no revocation needed')
}
View on GitHub (pinned to d3aa8bea5b)
Solutions
- Require the user to re-authorize the WeChat Official Account to obtain a fresh token pair
- Persist the refresh_token returned by WeChat's OAuth code exchange into the credential store
- Add a check upstream to route channels lacking refreshToken to re-auth instead of refresh
- Audit credential rows for null refresh_token and mark them for re-auth
Example fix
// before
await authProvider.refresh({ accessToken })
// after
if (!credential.refreshToken) {
await startReauthFlow(channelId)
} else {
await authProvider.refresh(credential)
} Defensive patterns
Strategy: validation
Validate before calling
if (!credential.refreshToken) {
scheduleReauth(channelId)
} else {
await authProvider.refresh(credential)
} Type guard
function hasRefreshToken(c: unknown): c is { refreshToken: string } {
return typeof (c as any)?.refreshToken === 'string' && (c as any).refreshToken.length > 0
} Try / catch
try {
await authProvider.refresh(input)
} catch (e) {
if (e?.code === 'ChannelAuthRefreshTokenMissing') {
await startReauthFlow(input.channelId)
return
}
throw e
} Prevention
- Always persist refresh_token from WeChat OAuth exchange
- Audit credentials for null refresh tokens
- Route refresh-less channels directly to re-auth
- Test OAuth flows end-to-end after WeChat API changes
When it happens
Trigger: Invoking refresh with input.refreshToken undefined/null — typically when the stored credential never captured a refresh token or it was lost during credential rotation.
Common situations: Legacy channel records created before refresh tokens were persisted, credentials imported manually, WeChat returning no refresh_token in the initial OAuth exchange (web-app vs snsapi flows).
Related errors
- ChannelRefreshTokenFailed
- ChannelAuthPlatformUidMissing
- ChannelAuthRefreshTokenMissing
- ChannelAccessTokenFailed
- ChannelAuthRefreshTokenMissing
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/8f938ac1ae6ef46c.
Report an issue: GitHub.