w7corp/easywechat · error · HttpException

Failed to get provider_access_token: %s

Error message

Failed to get provider_access_token: %s

What it means

Thrown by ProviderAccessToken::refresh() when the POST to cgi-bin/service/get_provider_token succeeds at HTTP level but the response body contains no provider_access_token key. The full WeChat response (with errcode/errmsg) is JSON-embedded in the exception message, so the real reason is the errcode, not the token itself. This is the service-provider (ISV) token for WeChat Work open platform APIs.

Source

Thrown at src/OpenWork/ProviderAccessToken.php:82

    public function toQuery(): array
    {
        return ['provider_access_token' => $this->getToken()];
    }

    /**
     * @throws HttpException
     */
    public function refresh(): string
    {
        $response = $this->httpClient->request('POST', 'cgi-bin/service/get_provider_token', [
            'json' => [
                'corpid' => $this->corpId,
                'provider_secret' => $this->providerSecret,
            ],
        ])->toArray(false);

        if (empty($response['provider_access_token'])) {
            throw new HttpException('Failed to get provider_access_token: '.\json_encode(
                $response,
                JSON_UNESCAPED_UNICODE
            ));
        }

        $this->cache->set($this->getKey(), $response['provider_access_token'], intval($response['expires_in']));

        return $response['provider_access_token'];
    }
}

View on GitHub (pinned to f0cf0a8b83)

Solutions

  1. Read the embedded JSON in the exception message and look up the errcode (40001 invalid secret, 60020 IP not in allowlist, 40013 invalid corpid)
  2. Verify corpid + provider_secret in the WeChat Work service-provider admin console (login as the provider, not a member corp)
  3. Add the outbound server IP to the provider IP allowlist and retry
  4. Clear the token cache key after fixing credentials so refresh() actually re-requests

Example fix

// before (wrong credentials)
$config = ['corp_id' => $memberCorpId, 'provider_secret' => $corpAppSecret];
// after (ISV provider credentials)
$config = [
    'corp_id' => $providerCorpId,          // the service provider's corpid
    'provider_secret' => $providerSecret,  // from provider admin console
    'secret' => $suiteSecret,
    'token' => ..., 'aes_key' => ...,
];
Defensive patterns

Strategy: try-catch

Validate before calling

$candidate = [$corpId, $providerSecret];
if (in_array(null, $candidate, true) || $providerSecret === '') {
    throw new \InvalidArgumentException('corp_id/provider_secret missing');
}

Try / catch

use EasyWeChat\Kernel\Exceptions\HttpException;
try {
    $token = $openWork->provider_access_token->getToken();
} catch (HttpException $e) {
    $body = json_decode(substr($e->getMessage(), strlen('Failed to get provider_access_token: ')), true);
    logger()->warning('provider token failed', ['errcode' => $body['errcode'] ?? null]);
    // 40001/60020 -> credentials/allowlist: do NOT retry;  -> alert
}

Prevention

When it happens

Trigger: Calling any OpenWork API that needs provider_access_token (e.g. getting auth corp info, corp token) after a cache miss. Fails when: provider_secret is wrong/revoked, corpid of the service provider is wrong, the secret belongs to a different suite/app, or the calling IP is not in the provider's IP allowlist (errcode 40001/40013/60020).

Common situations: Copied provider_secret from the wrong panel (corp app secret instead of provider secret); rotated secret but stale value in .env; server IP changed so allowlist blocks it; confusions between corpid of the ISV vs the authed corp.

Related errors


AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21). Data as JSON: /api/errors/c84526683b51a2b4. Report an issue: GitHub.