oauth-subscriber
oauth-subscriber copied to clipboard
Wrong signature for query string with duplicate parameter keys
When sending a request which uses a query containing duplicate parameter keys, the signature is incorrectly generated.
eg. ?parameter=myvalue¶mter=myvalue2
This is being caused by the usage of "http_build_query" instead of the Guzzle "build_query" function in "createBaseString".
Pull request: https://github.com/guzzle/oauth-subscriber/pull/70
I ran into the same issue today but for POST parameters with multiple values. For anyone experiencing this as well, here's how I fixed it.
1. Override the createBaseString
method
Create a new class that extends the Oauth1
class from this package, and override the createBaseString
method (which is only protected
, not private
) to use Query::build()
instead of http_build_query()
. This way the repeated parameters are encoded without []
.
<?php
namespace YourNamespace;
use GuzzleHttp\Psr7\Query;
use Psr\Http\Message\RequestInterface;
final class OAuth1 extends GuzzleHttp\Subscriber\Oauth\Oauth1
{
protected function createBaseString(RequestInterface $request, array $params): string
{
$url = (string) $request->getUri()->withQuery('');
$query = Query::build($params);
return strtoupper($request->getMethod())
. '&' . rawurlencode($url)
. '&' . rawurlencode($query);
}
}
Note: This may not work if you are still using Guzzle v6. In that case you can try the older \GuzzleHttp\Psr7\build_query()
function instead of Query::build()
but I cannot confirm that it fixes the issue.
Use this child class instead of GuzzleHttp\Subscriber\Oauth\Oauth1
as middleware in the Guzzle HandlerStack
.
2. Build the POST body yourself instead of using form_params
If you're sending a POST request with content-type application/x-www-form-urlencoded
and you're using the form_params
option to define the form data, Guzzle will encode it with []
for repeated parameters.
To avoid this, use the body
option instead and encode the POST data yourself using Query::build(...)
. See https://stackoverflow.com/questions/69411391/is-there-a-way-to-prevent-guzzle-from-appending-to-field-names-with-multiple
For example:
$formData = [
'parameter' => ['value1', 'value2'],
];
$options = [
'headers' => ['content-type' => 'application/x-www-form-urlencoded'],
'body' => Query::build($formData),
];
$response = $this->httpClient->request('POST', 'https://...', $options);
3. Make sure parameters with multiple values are sorted by their string value
In my case I had to send multiple integer values for the same parameter. To make sure the generated signature is correct, you need to sort them by their string value.
For example:
$parameter = [3, 222, 10];
sort($parameter, SORT_STRING); // Result: [10, 222, 3];
$formData = ['parameter' => $p];
$options = [
'headers' => ['content-type' => 'application/x-www-form-urlencoded'],
'body' => Query::build($formData),
];
$response = $this->httpClient->request('POST', 'https://...', $options);