Comunidade

Ask a Question
Back to all

WebHook não esta batendo os tokens.

Tenho um sistema de assinatura(php laravel) e após a assinatura recebo o payload do pagbank com o x-payload-signature (apenas na producao, não conseguir testar na homologaçao).
Fiz todo sistema de webhooks porem os tokens NUNCA batem, sempre ocorre Signature mismatch.
Ja tentei variad formas e na documentação esta MUITO confusa (https://developer.pagbank.com.br/reference/webhooks).
Meu codigo de validação esta assim, nao tenho nem ideia do que esta ocorrendo:


public function notification(Request $request)
{
    // =============================
    // 1. PAYLOAD CRU (CRÍTICO)
    // =============================
    $payload = $request->getContent();
    $headers = $request->headers->all();

    $sigPayload = $request->header('x-payload-signature');

    // =============================
    // 2. LOG / AUDITORIA
    // =============================
    $capture = [
        'received_at' => now()->toIso8601String(),
        'ip'          => $request->ip(),
        'method'      => $request->method(),
        'path'        => $request->path(),
        'headers'     => $headers,
        'body_raw'    => $payload,
        'body_json'   => json_decode($payload, true),
        'sha256'      => hash('sha256', $payload),
    ];

    $fname = 'pagbank/webhooks/' . now()->format('Ymd_His_u') . '-' . Str::random(6) . '.json';

    Storage::disk('local')->put(
        $fname,
        json_encode($capture, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
    );

    Log::channel('pagbank')->info('Webhook capture saved', [
        'file' => storage_path('app/' . $fname)
    ]);

    // =============================
    // 3. VALIDAÇÃO DA ASSINATURA
    // =============================
    if (app()->environment('production')) {

        if (!$sigPayload) {
            Log::channel('pagbank')->warning('Missing x-payload-signature');
            return response('Missing signature', 400);
        }

        // 🔑 BUSCA DA PUBLIC KEY DO PAGBANK
        $resp = json_decode($this->pagseguro->getPublicKey(), true);
        $publicKeyB64 = $resp['public_key'] ?? null;

        if (!$publicKeyB64) {
            Log::channel('pagbank')->error('Public key não retornada pelo PagBank');
            return response('Server misconfigured', 500);
        }

        $pubPem =
            "-----BEGIN PUBLIC KEY-----\n" .
            chunk_split($publicKeyB64, 64, "\n") .
            "-----END PUBLIC KEY-----\n";

        $pubKey = openssl_pkey_get_public($pubPem);

        if (!$pubKey) {
            Log::channel('pagbank')->error('openssl_pkey_get_public falhou', [
                'openssl_error' => openssl_error_string()
            ]);
            return response('Invalid public key', 500);
        }

        $sigBin = base64_decode($sigPayload, true);

        if ($sigBin === false) {
            Log::channel('pagbank')->warning('x-payload-signature inválido (base64)');
            return response('Invalid signature', 401);
        }

        $ok = openssl_verify(
            $payload,
            $sigBin,
            $pubKey,
            OPENSSL_ALGO_SHA256
        ) === 1;

        if (!$ok) {
            Log::channel('pagbank')->warning('Signature mismatch (x-payload-signature)', [
                'payload_sha256' => hash('sha256', $payload),
                'sig_base64'     => $sigPayload,
                'sig_hex'        => bin2hex($sigBin),
            ]);

            return response('Invalid signature', 401);
        }

        Log::channel('pagbank')->info('Signature OK (x-payload-signature)');
    }

    // =============================
    // 4. JSON VÁLIDO
    // =============================
    $data = json_decode($payload, true);

    if (json_last_error() !== JSON_ERROR_NONE) {
        Log::channel('pagbank')->warning('Invalid JSON payload');
        return response('Invalid JSON', 400);
    }

    // =============================
    // 5. PROCESSAMENTO
    // =============================
    \App\Jobs\ProcessaPagamento::dispatch($data)
        ->onQueue('webhooks');

    return response()->noContent(); // 204
}

a public-key esta vindo de uma requisição API /public-keys usando o token no header (recebo ela normal).

© 1996- Todos os direitos reservados.

PAGSEGURO INTERNET INSTITUIÇÃO DE PAGAMENTO S/A - CNPJ/MF 08.561.701/0001-01

Av. Brigadeiro Faria Lima, 1.384, São Paulo - SP - CEP 01451-001