Wei-Shaw/sub2api · error

auth.oidc.callbackMissingToken

Error message

auth.oidc.callbackMissingToken

What it means

In frontend/src/views/auth/WechatCallbackView.vue:817, finalizeCompletion() handles the WeChat OAuth exchange. Note the message key is 'auth.oidc.callbackMissingToken' (shared/reused OIDC key in the WeChat view) even though this is the WeChat callback. As with the other providers, a completion that is neither bind nor login (no access_token) triggers the throw.

Source

Thrown at frontend/src/views/auth/WechatCallbackView.vue:817

    states.includes('bind_login_required') ||
    states.includes('bind_login') ||
    states.includes('adopt_existing_user_by_email') ||
    states.includes('existing_account_required') ||
    states.includes('existing_account_binding_required')
}

async function finalizeCompletion(completion: PendingOAuthExchangeResponse, redirect: string) {
  if (getOAuthCompletionKind(completion) === 'bind') {
    const bindRedirect = sanitizeRedirectPath(completion.redirect || '/profile')
    clearPendingAuthSession()
    clearAllAffiliateReferralCodes()
    appStore.showSuccess(bindSuccessMessage)
    await router.replace(bindRedirect)
    return
  }

  if (!isOAuthLoginCompletion(completion)) {
    throw new Error(t('auth.oidc.callbackMissingToken'))
  }

  persistOAuthTokenContext(completion)
  await authStore.setToken(completion.access_token)
  clearAllAffiliateReferralCodes()
  appStore.showSuccess(t('auth.loginSuccess'))
  await router.replace(redirect)
}

async function finalizePendingAccountResponse(completion: PendingWeChatCompletion) {
  applyAdoptionSuggestionState(completion)
  const redirect = sanitizeRedirectPath(completion.redirect || redirectTo.value)

  if (completion.error === 'invitation_required') {
    pendingAccountAction.value = 'none'
    needsInvitation.value = true
    needsAdoptionConfirmation.value = false
    isProcessing.value = false

View on GitHub (pinned to 073e92d171)

Solutions

  1. Verify the WeChat appid/secret used by the backend exchange match the app that generated the QR/authorize URL.
  2. Ensure the auth code is exchanged immediately (single-use, 5-minute validity) and not re-exchanged on refresh — make the callback idempotent.
  3. Rename the i18n key to auth.wechat.callbackMissingToken (or add it) so the error is not misattributed to OIDC.
  4. Route non-bind/non-login completions to a friendly restart-login flow.

Example fix

// before
if (!isOAuthLoginCompletion(completion)) {
  throw new Error(t('auth.oidc.callbackMissingToken'))
}

// after
if (!isOAuthLoginCompletion(completion)) {
  appStore.showError(t('auth.wechat.callbackMissingToken'))
  await router.replace('/login')
  return
}
Defensive patterns

Strategy: type-guard

Type guard

function isWechatLoginCompletion(c: PendingOAuthExchangeResponse): c is PendingOAuthExchangeResponse & { access_token: string } {
  return getOAuthCompletionKind(c) !== 'bind' && typeof (c as any).access_token === 'string' && (c as any).access_token.length > 0;
}

Try / catch

try { await finalizeCompletion(completion, redirect); }
catch (e) {
  if (e.message === t('auth.oidc.callbackMissingToken')) { // note: reused OIDC key in WeChat view
    showError('WeChat login incomplete — please rescan');
    await router.replace('/login'); return;
  }
  throw e;
}

Prevention

When it happens

Trigger: WeChat code exchange returns 2xx without access_token: WeChat OAuth requires an app-specific secret and a server-side code-to-access_token exchange — a wrong appid/secret pairing, expired auth code (WeChat codes are single-use and short-lived ~5 min), or a session lost across the QR-scan redirect produces an empty completion.

Common situations: User scanning the WeChat QR then letting the code expire before confirming; mismatched WeChat Open Platform appid vs Official Account appid (unionid flows); cookie loss on mobile WeChat's embedded browser; the reused i18n key 'auth.oidc.*' misleading maintainers debugging WeChat.

Related errors


AI-assisted analysis of Wei-Shaw/sub2api@073e92d171 (2026-08-15). Data as JSON: /api/errors/c230b6f9e716a056. Report an issue: GitHub.