diff --git a/composer.json b/composer.json
index accb62e..22f1e26 100644
--- a/composer.json
+++ b/composer.json
@@ -3,9 +3,8 @@
     "description": "The Simple OAuth module for Drupal",
     "type": "drupal-module",
     "require": {
-        "league/oauth2-server": "^8.0 < 8.2",
-        "lcobucci/jwt": "^3.4",
-        "steverhoades/oauth2-openid-connect-server": "^1.1",
+        "league/oauth2-server": "^8.3",
+        "steverhoades/oauth2-openid-connect-server": "^1.3",
         "drupal/consumers": "^1.2",
         "php": ">=7.0"
     },
diff --git a/src/Entities/AccessTokenEntity.php b/src/Entities/AccessTokenEntity.php
index 9c077fe..b21c23a 100644
--- a/src/Entities/AccessTokenEntity.php
+++ b/src/Entities/AccessTokenEntity.php
@@ -2,10 +2,9 @@
 
 namespace Drupal\simple_oauth\Entities;
 
-use Lcobucci\JWT\Builder;
-use Lcobucci\JWT\Signer\Key;
+use Lcobucci\JWT\Configuration;
+use Lcobucci\JWT\Signer\Key\InMemory;
 use Lcobucci\JWT\Signer\Rsa\Sha256;
-use League\OAuth2\Server\CryptKey;
 use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
 use League\OAuth2\Server\Entities\Traits\AccessTokenTrait;
 use League\OAuth2\Server\Entities\Traits\EntityTrait;
@@ -18,31 +17,38 @@ class AccessTokenEntity implements AccessTokenEntityInterface {
   /**
    * {@inheritdoc}
    */
-  public function convertToJWT(CryptKey $privateKey) {
+  public function convertToJWT() {
     $private_claims = [];
-    \Drupal::moduleHandler()->alter('simple_oauth_private_claims', $private_claims, $this);
+    \Drupal::moduleHandler()
+      ->alter('simple_oauth_private_claims', $private_claims, $this);
     if (!is_array($private_claims)) {
       $message = 'An implementation of hook_simple_oauth_private_claims_alter ';
       $message .= 'returns an invalid $private_claims value. $private_claims ';
       $message .= 'must be an array.';
       throw new \InvalidArgumentException($message);
     }
-    $builder = (new Builder())
-      ->setAudience($this->getClient()->getIdentifier())
-      ->setId($this->getIdentifier(), TRUE)
-      ->setIssuedAt(time())
-      ->setNotBefore(time())
-      ->setExpiration($this->getExpiryDateTime()->getTimestamp())
-      ->setSubject($this->getUserIdentifier())
-      ->set('scopes', $this->getScopes());
+
+    $id = $this->getIdentifier();
+    $now = new \DateTimeImmutable('@' . \Drupal::time()->getCurrentTime());
+    $key_path = $this->privateKey->getKeyPath();
+    $key = InMemory::file($key_path);
+    $config = Configuration::forSymmetricSigner(new Sha256(), $key);
+
+    $builder = $config->builder()
+      ->permittedFor($this->getClient()->getIdentifier())
+      ->identifiedBy($id)
+      ->withHeader('jti', $id)
+      ->issuedAt($now)
+      ->canOnlyBeUsedAfter($now)
+      ->expiresAt($this->getExpiryDateTime())
+      ->relatedTo($this->getUserIdentifier())
+      ->withClaim('scopes', $this->getScopes());
 
     foreach ($private_claims as $claim_name => $value) {
-      $builder->set($claim_name, $value);
+      $builder->withClaim($claim_name, $value);
     }
 
-    $key = new Key($privateKey->getKeyPath(), $privateKey->getPassPhrase());
-    $token = $builder->sign(new Sha256(), $key)->getToken();
-    return $token;
+    return $builder->getToken($config->signer(), $config->signingKey());
   }
 
 }
diff --git a/tests/src/Functional/PasswordFunctionalTest.php b/tests/src/Functional/PasswordFunctionalTest.php
index 17a18a8..1cd385a 100644
--- a/tests/src/Functional/PasswordFunctionalTest.php
+++ b/tests/src/Functional/PasswordFunctionalTest.php
@@ -131,11 +131,11 @@ class PasswordFunctionalTest extends TokenBearerFunctionalTestBase {
         'code' => 401,
       ],
       'username' => [
-        'error' => 'invalid_credentials',
-        'code' => 401,
+        'error' => 'invalid_grant',
+        'code' => 400,
       ],
       'password' => [
-        'error' => 'invalid_credentials',
-        'code' => 401,
+        'error' => 'invalid_grant',
+        'code' => 400,
       ],
     ];
