Verifying a signature needs the raw body

A signature is computed over the exact bytes sent, and a framework that parses JSON into an array has already thrown those bytes away.

// wrong: re-encoding does not reproduce the bytes.
// key order, unicode escaping and float formatting differ.
$computed = hash_hmac('sha256', json_encode($request->all()), $secret);

// right
$computed = hash_hmac('sha256', $request->getContent(), $secret);

if (! hash_equals($signature, $computed)) {
    abort(400);
}

Round-tripping through a decoder and encoder changes the bytes in ways that are invisible until a payload contains a non-ASCII character or a float, at which point verification fails for a subset of legitimate requests. hash_equals rather than === is the other half: string comparison short-circuits on the first differing byte, which leaks timing information. Some frameworks consume the input stream during middleware, which makes getContent return empty and is worth checking early.