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

The scope argument for the ClientCredentials leads to a 400 Bad Request response #177

Closed
MurzNN opened this issue Jun 13, 2024 · 5 comments
Labels

Comments

@MurzNN
Copy link
Contributor

MurzNN commented Jun 13, 2024

Describe the bug
I'm migrating from the v1 to the v2 version of the library. In the v1 the scope argument worked well, but with v2 I'm receiving a 400 Bad Request response.

To Reproduce

  1. Pass the scope argument to the ClientCredentials constructor, like this:
const CLIENT_ID = 'my_client_id';
const CLIENT_SECRET = 'my_client_secret';
const SCOPE = 'manage_project';
$clientCredentials = new ClientCredentials(CLIENT_ID, CLIENT_SECRET, SCOPE);
  1. Get the 400 Bad Request response error:
Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST https://auth.us-central1.gcp.commercetools.com/oauth/token` resulted in a `400 Bad Request` response:
{"statusCode":400,"message":"Malformed parameter: scope: Invalid scope.","errors":[{"code":"invalid_scope","message":"Ma (truncated...)
 in /var/www/html/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113
  1. Remove the scope argument from the constructor, like this:
-$clientCredentials = new ClientCredentials(CLIENT_ID, CLIENT_SECRET, SCOPE);
+$clientCredentials = new ClientCredentials(CLIENT_ID, CLIENT_SECRET);

and see that the error disappears.

Expected behavior
The scope argument should not produce the error.

So, maybe in the v2 of the API, the scope should be passed via a different way?

Screenshots/Code snippet
Here is a code to reproduce the problem:

use Commercetools\Api\Client\ApiRequestBuilder;
use Commercetools\Api\Client\ClientCredentialsConfig;
use Commercetools\Api\Client\Config;
use Commercetools\Client\ClientCredentials;
use Commercetools\Client\ClientFactory;

require_once __DIR__ . '/vendor/autoload.php';

const CLIENT_ID = 'my_client_id';
const CLIENT_SECRET = 'my_client_secret';
const PROJECT_KEY = 'my_project_key';
const OAUTH_URL = 'https://auth.us-central1.gcp.commercetools.com/oauth/token';
const API_URL = 'https://api.us-central1.gcp.commercetools.com';
const SCOPE = 'manage_project';

$clientCredentials = new ClientCredentials(CLIENT_ID, CLIENT_SECRET, SCOPE);
// $clientCredentials = new ClientCredentials(CLIENT_ID, CLIENT_SECRET);
$authConfig = new ClientCredentialsConfig($clientCredentials, [], OAUTH_URL);

$config = new Config([], API_URL);
$client = ClientFactory::of()->createGuzzleClient($config, $authConfig);

$builder = new ApiRequestBuilder($client);
$request = $builder->withProjectKey(PROJECT_KEY)->get();
$response = $request->execute();

Stack information (please complete the following information):

  • PHP: 8.1
  • SDK: 10.3.0
@MurzNN MurzNN added the bug label Jun 13, 2024
@jenschude
Copy link
Contributor

jenschude commented Jun 13, 2024

Hi. Either omit the scope or use the scope including the project key ('manage_project:your-project-key')

@MurzNN
Copy link
Contributor Author

MurzNN commented Jun 14, 2024

But for what purposes the $scope argument is intended then?

function ClientCredentials::__construct(
    string $clientId,
    string $clientSecret,
    string $scope = null
)

Omitting the scope works well, but including it into the the project key - doesn't work:

const PROJECT_KEY = 'manage_project:drupal-connector';
$builder = new ApiRequestBuilder($client);
$request = $builder->withProjectKey(PROJECT_KEY)->get();

Produces a 404 error:

PHP Fatal error:  Uncaught GuzzleHttp\Exception\ClientException: Client error: `GET https://api.us-central1.gcp.commercetools.com/manage_project:drupal-connector` resulted in a `404 Not Found` response:
{"statusCode":404,"message":"Not found","errors":[{"code":"General","message":"Not found"}]}

@jenschude
Copy link
Contributor

The scope is needed when you have a client with multiple permissions but you want only a token for a specific scope, e.g.:

Client scope: manage_products:project_key manage_orders:project_key
Requested token scope: manage_products:project_key

And i didn't meant to use the scope in the project key, but to suffix the scope with it. The way it's presented in the MC. In the V1 SDK there was log to combine the scope and project key.

const CLIENT_ID = 'my_client_id';
const CLIENT_SECRET = 'my_client_secret';
const PROJECT_KEY = 'my_project_key';
const OAUTH_URL = 'https://auth.us-central1.gcp.commercetools.com/oauth/token';
const API_URL = 'https://api.us-central1.gcp.commercetools.com/';
const SCOPE = 'manage_project:my_project_key';

But as the oauth server will default a token request to the client permissions if the scope is being omitted. The best practice is to create a client in the Merchant Center with the needed permissions and omit the scope when requesting the token.

@MurzNN
Copy link
Contributor Author

MurzNN commented Jun 14, 2024

Thank you for the information! Will be good to document this too! ;)
Started to add PHPDoc to the ClientCredentials::__construct() like this:

  /**
   * The constructor of the ClientCredentials class.
   *
   * @param string $clientId
   *   The client id.
   * @param string $clientSecret
   *   The client secret.
   * @param string $scope
   *   The scope is needed when you have a client with multiple permissions
   *   but you want only a token for a specific scope.
   *   Format: `<the scope name>:<the project key>`.
   *   Example: `manage_products:project1`.
   */
  public function __construct(string $clientId, string $clientSecret, string $scope = NULL) {
    $this->clientId = $clientId;
    $this->clientSecret = $clientSecret;
    $this->scope = $scope;
    $this->cacheKey = sha1($clientId . (string) $scope);
  }

but saw that it is auto-generated, so just extended the readme and created a PR #178 - please review.

And maybe we still can add PHPDocs to the autogenerated files somehow?

@barbara79
Copy link
Contributor

barbara79 commented Jul 4, 2024

Thanks for your contribution @MurzNN 💯
Consider that we also have this documentation which I am updating with your suggestions, and adding the DocBlock in the ClientCredentials class.
As well as the technical documentation

I would close this issue, but please feel free to open another one if you have any problems

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

No branches or pull requests

3 participants