- Issue created by @pbosmans
- Status changed to Closed: works as designed
about 1 year ago 10:06pm 3 September 2023 - πΊπΈUnited States fathershawn New York
The optionProvider on Client Credentials solves this issue: #3157501: Add Scopes to ClientCredentials Grant Type β . Rather than using the upstream default class, you should extend
\Drupal\oauth2_client\OAuth2\Client\OptionProvider\ClientCredentialsOptionProvider
in your own custom class and I think you can copy right over the code from\League\OAuth2\Client\OptionProvider\HttpBasicAuthOptionProvider::getAccessTokenOptions
as it adds what it does onto the options configured by the parent. Your extension will pass the check in the code that you have removed. - Status changed to Active
about 1 year ago 11:50am 27 October 2023 - π§πͺBelgium pbosmans
I've created our own custom class as you suggested, but how can i add the scopes to the request.
My optionprovider is created in the Oauth2ClientPluginBase.php at line 211 => $collaboratorObjects[$type] = new $collaborator();
I can't use tesame method like the ClientCredentials option providor => $provider->setOptionProvider(new ClientCredentialsOptionProvider($clientPlugin));
It has a parameter and the custom optionsprovider not. - Status changed to Postponed: needs info
about 1 year ago 2:46pm 27 October 2023 - πΊπΈUnited States fathershawn New York
I wouldn't set this option provider via the annotation method (which is used at
Oauth2ClientPluginBase:211
as you note). I would leave that off and in your plugin, override and extendOauth2ClientPluginBase::getProvider
.Assuming:
class SomeServiceAuthOptionProvider extends ClientCredentialsOptionProvider { public function getAccessTokenOptions($method, array $params) { // copied from \League\OAuth2\Client\OptionProvider\HttpBasicAuthOptionProvider if (empty($params['client_id']) || empty($params['client_secret'])) { throw new InvalidArgumentException('clientId and clientSecret are required for http basic auth'); } $encodedCredentials = base64_encode(sprintf('%s:%s', $params['client_id'], $params['client_secret'])); unset($params['client_id'], $params['client_secret']); $options = parent::getAccessTokenOptions($method, $params); $options['headers']['Authorization'] = 'Basic ' . $encodedCredentials; return $options; } }
In your plugin, the override would be
public function getProvider(): GenericProvider { $provider = parent::getProvider(); $client = $this->getClient(); $provider->setOptionProvider(new SomeServiceAuthOptionProvider($clientPlugin)); return $provider; }
Then the provider will be set when the code flow gets to
ClientCredentials::getAccessToken
and it will be an instance ofClientCredentialsOptionProvider
- Status changed to Closed: works as designed
about 1 year ago 9:22am 30 October 2023 - π§πͺBelgium pbosmans
Thank you very much for your response, it solved the issue.
Here are my changes for others who has tesame issues
My custom optionprovider :class UcllHttpBasicAuthOptionProvider extends ClientCredentialsOptionProvider { /** * A string of scopes imploded from the Oauth2ClientPlugin. */ private string $scopeOption; public function __construct(Oauth2ClientPluginInterface $clientPlugin) { $scopes = $clientPlugin->getScopes(); if (!empty($scopes)) { $this->scopeOption = implode($clientPlugin->getScopeSeparator(), $scopes); } } public function getAccessTokenOptions($method, array $params) { if (empty($params['client_id']) || empty($params['client_secret'])) { throw new InvalidArgumentException('clientId and clientSecret are required for http basic auth'); } $encodedCredentials = base64_encode(sprintf('%s:%s', $params['client_id'], $params['client_secret'])); unset($params['client_id'], $params['client_secret']); if (!empty($this->scopeOption)) { $params['scope'] = $this->scopeOption; } $options = parent::getAccessTokenOptions($method, $params); $options['headers']['Authorization'] = 'Basic ' . $encodedCredentials; return $options; } }
My oauth2client plugin :
/** * OAuth2 Client to authenticate with our services * * The client_id and client_secret is set through /admin/config/system/oauth2-client * * @Oauth2Client( * id = "<your-client-id>", * name = @Translation("<YOUR CLIENT NAME>"), * grant_type = "client_credentials", * token_uri = "https://<your-domain>/oauth2/token", * authorization_uri = "", * resource_owner_uri = "", * scopes = { "<your-scopes>" }, * ) */ class UcllApi extends Oauth2ClientPluginBase { use StateTokenStorage; /** * {@inheritdoc} */ public function getProvider(): GenericProvider { $provider = parent::getProvider(); $provider->setOptionProvider(new UcllHttpBasicAuthOptionProvider($this)); return $provider; } /** * {@inheritdoc} */ public function getRedirectUri(): string { return ""; } }
- πΊπΈUnited States fathershawn New York
Happy to help and glad it worked out!