Stack Exchange
Braintree webhooks: Error: payload contains illegal characters
I am trying to consume Braintree webhooks in a java microservice (Micronaut fwiw).
The issue that I'm having is that when I try to parse the webhook body, I get an error: " Error: payload contains illegal characters", which it does. So I'm wondering if maybe I'm casting the request body to something thats inserting the characters...? (the body is x-www-form-urlencoded)
package com.autonomy;

import com.braintreegateway.*;
import event_broker.BrokerServiceGrpc;
import event_broker.EventBroker;
import events.Events;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.micronaut.context.annotation.Value;
import io.micronaut.http.HttpStatus;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Body;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Post;
import io.micronaut.http.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.Normalizer;
import java.time.Clock;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;


@Controller("/webhooks")
public class WebhooksController {
    private final Logger logger = LoggerFactory.getLogger("BraintreeServiceJava");

    @Value("${env}") String env;
    @Value("${braintree.merchant.id}") String braintreeMerchantId;
    @Value("${braintree.public.key}") String braintreePublicKey;
    @Value("${braintree.private.key}") String braintreePrivateKey;
    
    @Post(consumes = MediaType.APPLICATION_FORM_URLENCODED)
    public HttpResponse<?> consumeWebhook(@Body String body) {
        BraintreeGateway gateway =
                new BraintreeGateway(determineEnv(env),
                        braintreeMerchantId,
                        braintreePublicKey,
                        braintreePrivateKey
                );
        logger.info(body);
        try {
            String decodedBody = body; // was doing a decode here that didn't do anything
            logger.info(decodedBody);
            Map<String, String> map = new HashMap<>();
            Arrays.stream(decodedBody.split("&")).toList().forEach(pair -> {
                String[] param = pair.split("=");
                map.put(param[0], param[1]);
            });
            WebhookNotification webhookNotification = gateway.webhookNotification().parse(
                    map.get("bt_signature"),
                    map.get("bt_payload")
            );
            
        ..... Do stuff

        } catch (Exception e) {
            logger.error(String.format("Braintree webhook failed for %s. Error: %s", kind, e.getMessage()), e);
            return HttpResponse.status(HttpStatus.BAD_REQUEST);
        }

        return HttpResponse.status(HttpStatus.OK);
    }

    private Environment determineEnv(String env) {
        if (env.equals("beta") || env.equals("prod")) {
            return Environment.PRODUCTION;
        } else {
            return Environment.SANDBOX;
        }
    }
}


Try:
@Post(consumes = MediaType.APPLICATION_FORM_URLENCODED)
public HttpResponse<?> consumeWebhook(String bt_signature, String bt_payload)

BTW: What 'illegal characters' were in the body that was logged?

In Java with Quarkus, instead of using

@Body String body

as the parameters are of type x-www-form-urlencoded you can use

@FormParam("bt_signature") String btSignature,
@FormParam("bt_payload") String btPayload.

What your problem refers to, may be solved by doing a whitespace replace with a line break. Because the braintree library parse has the following validation regex, and in btPayload I have encountered whitespace:
private static final Pattern PAYLOAD_CHARS_PATTERN = Pattern.compile("[^A-Za-z0-9+=/\n]"

Solution:
btPayload = btPayload.replaceAll(" ", "\n");
WebhookNotification webhookNotification = gateway.webhookNotification()
                    .parse(btSignature, btPayload);

