Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong signature for query string with duplicate parameter keys #69

Open
wtrv opened this issue Oct 10, 2018 · 2 comments
Open

Wrong signature for query string with duplicate parameter keys #69

wtrv opened this issue Oct 10, 2018 · 2 comments

Comments

@wtrv
Copy link

wtrv commented Oct 10, 2018

When sending a request which uses a query containing duplicate parameter keys, the signature is incorrectly generated.

eg. ?parameter=myvalue&paramter=myvalue2

This is being caused by the usage of "http_build_query" instead of the Guzzle "build_query" function in "createBaseString".

@wtrv
Copy link
Author

wtrv commented Oct 10, 2018

Pull request: #70

@bertramakers
Copy link

bertramakers commented Jan 3, 2023

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);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants