1

I have a custom service and in the custom service, I want to generate a new Bearer token for the current user ( it's logged in) with simple_oauth module. in its documentation is has not mentioned how can I generate new a new token for current logged in user. So, how can I generate a new Bearer token for current logged in user?

2 Answers 2

2

I assume you need an access token for some API call, so to have it generated automatically when you call some API method in your service.

I usually go with the following set up:

  1. Install kamermans/guzzle-oauth2-subscriber with composer
  2. Define config my_module.auth.yml and import it
client_id: test
client_secret: test
base_uri: 'https://some-external-service/auth/token'
  1. Create the following services/factories my_module.services.yml
services:
  my_module.handler_stack:
    class: GuzzleHttp\HandlerStack
    factory: ['GuzzleHttp\HandlerStack', 'create']
    calls:
      - [push, ['@my_module.oauth2_middleware']]

  my_module.client_factory:
    class: Drupal\my_module\Client\ClientFactory
    arguments: ['@config.factory']
   
  my_module.oauth2_middleware_factory:
    class: Drupal\my_module\Auth\OAuth2MiddlewareFactory
    arguments: ['@config.factory']

  my_module.oauth2_middleware.client:
    class: GuzzleHttp\Client
    factory: 'my_module.client_factory:createClient'
    arguments:
      - 'my_module.auth'

  my_module.oauth2_middleware:
    class: kamermans\OAuth2\OAuth2Middleware
    factory: 'my_module.oauth2_middleware_factory:createMiddleware'
    arguments:
      - '@my_module.oauth2_middleware.client'
      - 'my_module.auth'    
  1. Define your middleware factory OAuth2MiddlewareFactory.php
<?php

namespace Drupal\my_module\Auth;

use Drupal\Core\Config\ConfigFactoryInterface;
use GuzzleHttp\ClientInterface;
use kamermans\OAuth2\GrantType\ClientCredentials;
use kamermans\OAuth2\OAuth2Middleware;

/**
 * Factory for OAuth2 Guzzle middleware, configured from configuration objects.
 *
 * @package Drupal\my_module\Auth
 */
class OAuth2MiddlewareFactory {
  
  /**
   * The configuration factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  private $configFactory;

  /**
   * OAuth2MiddlewareFactory constructor.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The configuration factory to use.
   */
  public function __construct(ConfigFactoryInterface $configFactory) {
    $this->configFactory = $configFactory;
  }

  /**
   * Creates an OAuth2 Guzzle Middleware.
   *
   * @param \GuzzleHttp\ClientInterface $client
   *   The guzzle HTTP client to use for obtaining client credentials.
   * @param string $configName
   *   Name of the configuration object to use.
   *
   * @return \kamermans\OAuth2\OAuth2Middleware
   *   The Guzzle Oauth2 middleware.
   */
  public function createMiddleware(ClientInterface $client, string $configName): OAuth2Middleware {
    $configuration = $this->configFactory->get($configName);

    $reauth_config = [
      'client_id' => $configuration->get('client_id'),
      'client_secret' => $configuration->get('client_secret'),
      'state' => time(),
    ];

    if ($configuration->get('scope')) {
      $reauth_config['scope'] = $configuration->get('scope');
    }

    $grant_type = new ClientCredentials($client, $reauth_config);

    return new OAuth2Middleware($grant_type);
  }

}
  1. Define client factory ClientFactory.php
<?php

namespace Drupal\my_module\Client;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;

/**
 * Factory for Guzzle HTTP clients, configured from configuration objects.
 *
 * @package Drupal\my_module\Client
 */
class ClientFactory {
  
  /**
   * The configuration object factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * ClientFactory constructor.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The configuration object factory.
   */
  public function __construct(ConfigFactoryInterface $configFactory) {
    $this->configFactory = $configFactory;
  }

  /**
   * Creates a Guzzle HTTP client.
   *
   * @param string $configName
   *   Name of the configuration object to use.
   * @param array $clientConfig
   *   Additional configuration settings for the Guzzle HTTP client.
   *
   * @return \GuzzleHttp\Client
   *   A configured Guzzle HTTP client.
   */
  public function createClient(string $configName, array $clientConfig = []): Client {
    $config = $this->configFactory->get($configName);

    $prepared_config = $this->prepareClientConfig($config, $clientConfig);

    return new Client(
      $prepared_config
    );
  }

  /**
   * Prepares the configuration of the Guzzle HTTP client.
   *
   * Priority of the configuration:
   *   1. configuration in $config, limited to certain common settings
   *   2. configuration in $clientConfig passed in via the service container
   *   3. defaults set in this method.
   *
   * @param \Drupal\Core\Config\ImmutableConfig $config
   *   The configuration object to use.
   * @param array $clientConfig
   *   Additional configuration settings for the Guzzle HTTP client.
   *
   * @return array
   *   The client configuration.
   */
  protected function prepareClientConfig(ImmutableConfig $config, array $clientConfig = []): array {
    $prepared_config = $clientConfig;

    $prepared_config['base_uri'] = $config->get('base_uri');

    $defaults = [
      RequestOptions::TIMEOUT => $clientConfig[RequestOptions::TIMEOUT] ?? 10,
      RequestOptions::CONNECT_TIMEOUT => $clientConfig[RequestOptions::TIMEOUT] ?? 10,
    ];

    foreach (array_keys($defaults) as $option) {
      $prepared_config[$option] = $config->get($option) ?? $defaults[$option];
    }

    return $prepared_config;
  }

}

  1. Define your client by using the factory in my_module.services.yml
  my_module.my_service.client:
    class: GuzzleHttp\Client
    factory: 'my_module.client_factory:createClient'
    arguments:
      - 'my_module.my_service'
      - auth: oauth
        handler: '@my_module.handler_stack'

where my_module.my_service.yml is

base_uri: 'https://some-external-service/a-service-namespace/'
  1. Create your service that will trigger API by using the client you created by the factory earlier
  my_module.service.region:
    class: Drupal\my_module\Service\MyService
    arguments: ['@my_module.my_service.client']

and this is MyService.php

<?php

namespace Drupal\my_module\Service\Region;

use GuzzleHttp\ClientInterface;

/**
 * API client for my service.
 *
 * @package Drupal\my_module\Service
 */
class MyService {
  
  /**
   * A guzzle HTTP client.
   *
   * @var \GuzzleHttp\ClientInterface
   */
  private $client;

  /**
   * MyService constructor.
   *
   * @param \GuzzleHttp\ClientInterface $client
   *   A Guzzle HTTP client.
   */
  public function __construct(ClientInterface $client) {
    $this->client = $client;
  }

  /**
   * Finds something from the my service.
   *
   * @param string $langCode
   *   The language code.
   * @param string $postalCode
   *   The postal code.
   *
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  public function findSomething(string $langCode, string $value): Region {
    $response = $this->client->request('GET', 'my-service-uri/find',
      [
        'headers' => [
          'Accept' => 'application/json',
          'Accept-Language' => $langCode,
        ],
        'query' => [
          'value' => $value,
        ],
      ]
    );

    $json = $response->getBody()->getContents();

    // Do something here, you may use serializer to deserialize the content
    // here with the custom defined model or some other fancy stuff.

  }

}

This might too much, but you may find some useful code

0

POST request to /oauth/token generates a new token (don't forget to add proper body params)

You can also use a refresh token to generate a new access token by using grant_type 'refresh_token'

3
  • thanks for you attention. yes, I knew this solution but I'm looking for a better solution. :)
    – Yuseferi
    May 12, 2020 at 17:40
  • additionally, the grant_type is password and I don't have all users' passwords. so it's better to use another solution.
    – Yuseferi
    May 12, 2020 at 18:10
  • password grant type is now deprecated in the latest version of the module and is no longer available to generate tokens
    – anoopjohn
    Nov 21, 2023 at 23:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.