diff --git a/src/Controller/Oauth2Token.php b/src/Controller/Oauth2Token.php
index 954cab875b938243cbb074c5d2d1b1c3c354e9d9..c0f31e20dcf5adc57be4724c5433f43554fbdfef 100644
--- a/src/Controller/Oauth2Token.php
+++ b/src/Controller/Oauth2Token.php
@@ -2,7 +2,10 @@
 
 namespace Drupal\simple_oauth\Controller;
 
+use Drupal\Component\Serialization\Json;
+use Drupal\Component\Utility\Crypt;
 use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Lock\LockBackendInterface;
 use Drupal\simple_oauth\Server\AuthorizationServerFactoryInterface;
 use GuzzleHttp\Psr7\Response;
 use League\OAuth2\Server\Exception\OAuthServerException;
@@ -40,6 +43,13 @@ class Oauth2Token extends ControllerBase {
    */
   protected ClientRepositoryInterface $clientRepository;
 
+  /**
+   * The lock backend.
+   *
+   * @var \Drupal\Core\Lock\LockBackendInterface
+   */
+  protected LockBackendInterface $lock;
+
   /**
    * The simple_oauth logger channel.
    *
@@ -56,6 +66,8 @@ class Oauth2Token extends ControllerBase {
    *   The PSR-7 converter.
    * @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $client_repository
    *   The client repository service.
+   * @param \Drupal\Core\Lock\LockBackendInterface $lock
+   *   The lock backend.
    * @param \Psr\Log\LoggerInterface $logger
    *   The simple_oauth logger channel.
    */
@@ -63,11 +75,13 @@ class Oauth2Token extends ControllerBase {
     AuthorizationServerFactoryInterface $authorization_server_factory,
     HttpMessageFactoryInterface $http_message_factory,
     ClientRepositoryInterface $client_repository,
+    LockBackendInterface $lock,
     LoggerInterface $logger,
   ) {
     $this->authorizationServerFactory = $authorization_server_factory;
     $this->httpMessageFactory = $http_message_factory;
     $this->clientRepository = $client_repository;
+    $this->lock = $lock;
     $this->logger = $logger;
   }
 
@@ -79,6 +93,7 @@ class Oauth2Token extends ControllerBase {
       $container->get('simple_oauth.server.authorization_server.factory'),
       $container->get('psr7.http_message_factory'),
       $container->get('simple_oauth.repositories.client'),
+      $container->get('lock'),
       $container->get('logger.channel.simple_oauth')
     );
   }
@@ -99,7 +114,18 @@ class Oauth2Token extends ControllerBase {
     $server_response = new Response();
     $client_id = $request->get('client_id');
 
+    $lock_key = $this->createLockKey($request);
+
     try {
+      // Try to acquire the lock.
+      while (!$this->lock->acquire($lock_key)) {
+        // If we can't acquire the lock, wait for it.
+        if ($this->lock->wait($lock_key)) {
+          // Timeout reached after 30 seconds.
+          throw OAuthServerException::accessDenied('Request timed out. Could not acquire lock.');
+        }
+      }
+
       if (empty($client_id)) {
         throw OAuthServerException::invalidRequest('client_id');
       }
@@ -120,8 +146,28 @@ class Oauth2Token extends ControllerBase {
       );
       $response = $exception->generateHttpResponse($server_response);
     }
+    finally {
+      // Release the lock.
+      $this->lock->release($lock_key);
+    }
 
     return $response;
   }
 
+  /**
+   * Creates a lock key for the request.
+   *
+   * The key consists of the request content, in this case the
+   * grant payload.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request.
+   *
+   * @return string
+   *   The lock key.
+   */
+  protected function createLockKey(Request $request): string {
+    return Crypt::hashBase64(Json::encode($request->request->all()));
+  }
+
 }