Even when Scopes are declared in the annotations, they are ignored and not sent during Token Request.
So authorization request with grant_type='client_credentials' fails.

I am creating a patch that includes Scopes in the getAccessToken function.

Also, Scopes format of array (in the README file) do not work. Scopes should be declared as comma delimited string as shown below. Conversation around this can also be found on thephpleague php library being used for this module: https://github.com/thephpleague/oauth2-client/issues/464

Patch coming. Here are the scopes declaration that work below. Read me also updated.


namespace Drupal\my_module\Plugin\Oauth2Client;
use Drupal\oauth2_client\Plugin\Oauth2Client\Oauth2ClientPluginBase;

/**
 * OAuth2 Client to authenticate with ExampleClient
 *
 * @Oauth2Client(
 *   id = "example",
 *   name = @Translation("Example"),
 *   grant_type = "client_credentials",
 *   client_id = "###",
 *   client_secret = "###",
 *   authorization_uri = "",
 *   token_uri = "https://example.com/oauth2/token",
 *   redirect_uri = "",
 *   resource_owner_uri = "https://example.com/JobRequisitionDetails",
 *   scopes = "jobrequisition:read, jobstuff:read",
 *   scope_separator = ",",
 * )
 */
class ExampleClient extends Oauth2ClientPluginBase {}
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

Jumoke created an issue. See original summary.

jumoke’s picture

Issue summary: View changes
jumoke’s picture

Here is the patch to add scope correctly to your token request.

jumoke’s picture

Issue summary: View changes
imclean’s picture

There is a current GitLab issue addressing this problem: https://github.com/thephpleague/oauth2-client/issues/774#issuecomment-64...

imclean’s picture

Scopes can be defined using object notation.

 *   scopes = {
 *    "https://api.payments.auspost.com.au/payhive/payments/read",
 *    "https://api.payments.auspost.com.au/payhive/payments/write",
 *   },

Use this with the change I suggested in the GitLab issue linked to in #5.

Also see: #3046879: Change optionprovider to get the token

imclean’s picture

Status: Active » Closed (duplicate)
+++ b/README.md
@@ -62,7 +62,7 @@ namespace Drupal\oauth2_client\Plugin\Oauth2Client;
+ *   scopes = "basic, firebase, openid",

This is not correct. It should be a json object, see #3150757: Fix scopes documentation in README.md. The module just needs to be fixed to use it properly. See the other issues.

I think this is a duplicate of other issues, unless you can point out what this does which is different.

zerbash’s picture

Version: 8.x-2.x-dev » 8.x-3.x-dev
Assigned: jumoke » Unassigned
Status: Closed (duplicate) » Needs work

Since Oauth2ClientPluginBase is designed to handle scopes, it should work with the declared scopes, rather than having to #3046879: Change optionprovider to get the token or use #3256272: Additional parameters to get Access token.

Something along the lines of the second half of jumoke's patch:

$client = $this->getClient($clientId);
$options = ['scope' => $client->getScopes()];

$accessToken = $provider->getAccessToken('client_credentials', $options);

This MR provides a workaround:


 // Declared in custom plugin
  public function getRequestOptions() {
    return [
      'scope' => 'student_logistics_requests:create'
    ];
  }
 // ClientCredentialsGrantService.php
    $client = $this->getClient($pluginId);
    $provider = $this->getProvider($pluginId);
    $options = array_merge(['code' => $code], $client->getRequestOptions());

...but it sure would be cleaner to just use the 'scopes' declared in the plugin annotation.

fathershawn’s picture

Assigned: Unassigned » fathershawn
fathershawn’s picture

Status: Needs work » Postponed (maintainer needs more info)

I'm not clear on how we are not already using scopes with the code as it is:

They are a named parameter in the upstream GenericProvider.

We populate that parameter from our plugin definition

/**
   * Creates a new provider object.
   *
   * @param string $pluginId
   *   The client for which a provider should be created.
   *
   * @return \League\OAuth2\Client\Provider\GenericProvider
   *   The provider of the OAuth2 Server.
   *
   * @throws \Drupal\oauth2_client\Exception\InvalidOauth2ClientException
   *   Exception thrown when trying to retrieve a non-existent OAuth2 Client.
   */
  protected function getProvider($pluginId) {
    if (isset($this->clientProviderCache[$pluginId])) {
      $provider = $this->clientProviderCache[$pluginId];
    }
    else {
      $client = $this->getClient($pluginId);

      $provider = new GenericProvider([
        'clientId' => $client->getClientId(),
        'clientSecret' => $client->getClientSecret(),
        'redirectUri' => $client->getRedirectUri(),
        'urlAuthorize' => $client->getAuthorizationUri(),
        'urlAccessToken' => $client->getTokenUri(),
        'urlResourceOwnerDetails' => $client->getResourceUri(),
        'scopes' => $client->getScopes(),
        'scopeSeparator' => $client->getScopeSeparator(),
      ]);
      $this->clientProviderCache[$pluginId] = $provider;
    }
    return $provider;
  }

Most of which is code inherited from previous maintainers, but if I add scopes = {"foo", "bar"} to a plugin annotation and inspect the instantiated provider at the return above, the scopes property in the GenericProvder is properly initialized with the expected array.

fathershawn’s picture

Status: Postponed (maintainer needs more info) » Needs work

I found an upstream issue: [Question] Client Credentials Grant with scope which lead to a deeper exploration of the Oauth2 Client library code.

Our scopes property in the plugin definition gets passed to the GenericProvider as shown in #11 and becomes \League\OAuth2\Client\Provider\GenericProvider::$scopes . Within the library, that property is accessed via GenericProvider::getDefaultScopes which is only called in the library by \League\OAuth2\Client\Provider\AbstractProvider::getAuthorizationParameters which is only used to build the url for \Drupal\oauth2_client\Service\Grant\AuthorizationCodeGrantService::getAccessToken

Following the guidance of that issue, I propose to create a ClientCredentialsOptionProvider and inject it before the access token is requested our Client Credentials service

fathershawn’s picture

Status: Needs work » Fixed

Successfully tested on my current project

  • FatherShawn committed f7479af on 8.x-3.x
    Issue #3157501 by FatherShawn: Add Scopes to ClientCredentials Grant...
fathershawn’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.