diff --git a/simple_oauth.module b/simple_oauth.module
index 1a1ba00..4c8cee0 100644
--- a/simple_oauth.module
+++ b/simple_oauth.module
@@ -105,7 +105,7 @@ function simple_oauth_form_consumer_form_alter(array &$form, FormStateInterface
   $default_value = reset($admin_roles);
   unset($form['roles']['widget']['#options'][$default_value]);
   $recommendation_text = t(
-    'Create a <a href=":url">role</a> for every logical group of permissions you want to make available to a consumer.',
+    'Create a <a href=":url">role</a> for every logical group of permissions you want to make available to a consumer. A user using this consumer will never be granted more roles than the selected in this list. A user will never be granted roles they don\'t previously have, regardless of the configuration in this field.',
     [':url' => Url::fromRoute('entity.user_role.collection')->toString()]
   );
   $form['roles']['widget']['#description'] .= '<br>' . $recommendation_text;
diff --git a/simple_oauth_extras/simple_oauth_extras.routing.yml b/simple_oauth_extras/simple_oauth_extras.routing.yml
index 54da7c9..0b8c533 100644
--- a/simple_oauth_extras/simple_oauth_extras.routing.yml
+++ b/simple_oauth_extras/simple_oauth_extras.routing.yml
@@ -9,15 +9,3 @@ oauth2_token_extras.authorize:
   options:
     _auth: ['cookie']
     no_cache: TRUE
-
-oauth2_token.user_debug:
-  path: '/oauth/debug'
-  defaults:
-    _controller: 'Drupal\simple_oauth_extras\Controller\DebugController::debug'
-  methods: [GET]
-  requirements:
-    _access: 'TRUE'
-    _format: 'json'
-  options:
-    _auth: ['oauth2']
-    no_cache: TRUE
diff --git a/simple_oauth_extras/tests/simple_oauth_extras_test/simple_oauth_extras_test.routing.yml b/simple_oauth_extras/tests/simple_oauth_extras_test/simple_oauth_extras_test.routing.yml
index 6b4c5fa..287c43e 100644
--- a/simple_oauth_extras/tests/simple_oauth_extras_test/simple_oauth_extras_test.routing.yml
+++ b/simple_oauth_extras/tests/simple_oauth_extras_test/simple_oauth_extras_test.routing.yml
@@ -6,3 +6,15 @@ oauth2_token_extras.test_token:
   methods: [GET]
   requirements:
     _access: 'TRUE'
+
+oauth2_token.user_debug:
+  path: '/oauth/debug'
+  defaults:
+    _controller: 'Drupal\simple_oauth_extras_test\Controller\DebugController::debug'
+  methods: [GET]
+  requirements:
+    _access: 'TRUE'
+    _format: 'json'
+  options:
+    _auth: ['oauth2']
+    no_cache: TRUE
diff --git a/simple_oauth_extras/src/Controller/DebugController.php b/simple_oauth_extras/tests/simple_oauth_extras_test/src/Controller/DebugController.php
similarity index 96%
rename from simple_oauth_extras/src/Controller/DebugController.php
rename to simple_oauth_extras/tests/simple_oauth_extras_test/src/Controller/DebugController.php
index d312f60..ec033c2 100644
--- a/simple_oauth_extras/src/Controller/DebugController.php
+++ b/simple_oauth_extras/tests/simple_oauth_extras_test/src/Controller/DebugController.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\simple_oauth_extras\Controller;
+namespace Drupal\simple_oauth_extras_test\Controller;
 
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\user\PermissionHandlerInterface;
diff --git a/simple_oauth_extras/tests/src/Functional/RolesNegotiationFunctionalTest.php b/simple_oauth_extras/tests/src/Functional/RolesNegotiationFunctionalTest.php
index e788849..14b6355 100644
--- a/simple_oauth_extras/tests/src/Functional/RolesNegotiationFunctionalTest.php
+++ b/simple_oauth_extras/tests/src/Functional/RolesNegotiationFunctionalTest.php
@@ -3,8 +3,8 @@
 namespace Drupal\Tests\simple_oauth_extras\Functional;
 
 use Drupal\Component\Serialization\Json;
-use Drupal\Core\Url;
 use Drupal\consumers\Entity\Consumer;
+use Drupal\Core\Url;
 use Drupal\Tests\BrowserTestBase;
 use Drupal\Tests\simple_oauth\Functional\RequestHelperTrait;
 use Drupal\Tests\simple_oauth\Functional\SimpleOauthTestTrait;
@@ -22,6 +22,7 @@ class RolesNegotiationFunctionalTest extends BrowserTestBase {
     'image',
     'simple_oauth',
     'simple_oauth_extras',
+    'simple_oauth_extras_test',
     'text',
     'user',
   ];
@@ -92,8 +93,16 @@ class RolesNegotiationFunctionalTest extends BrowserTestBase {
     ]);
     $role->grantPermission('delete own simple_oauth entities');
     $role->save();
+    $role = Role::create([
+      'id' => 'rab',
+      'label' => 'Rab',
+      'is_admin' => FALSE,
+    ]);
+    $role->grantPermission('update own simple_oauth entities');
+    $role->save();
     $this->user->addRole('foo');
     $this->user->addRole('bar');
+    $this->user->addRole('rab');
     $this->user->save();
 
     // Create a Consumer.
@@ -103,7 +112,11 @@ class RolesNegotiationFunctionalTest extends BrowserTestBase {
       'label' => $this->getRandomGenerator()->name(),
       'secret' => $this->clientSecret,
       'confidential' => TRUE,
-      'roles' => [['target_id' => 'oof']],
+      'roles' => [
+        ['target_id' => 'oof'],
+        ['target_id' => 'foo'],
+        ['target_id' => 'bar'],
+      ],
     ]);
     $this->client->save();
 
@@ -111,24 +124,13 @@ class RolesNegotiationFunctionalTest extends BrowserTestBase {
   }
 
   /**
-   * Test access to own published node with missing role on User entity.
+   * Makes sure that the roles in the consumer and the user are granted.
    */
-  public function testRequestWithRoleRemovedFromUser() {
+  public function testTokenWithTwoRoles() {
     $access_token = $this->getAccessToken(['foo', 'bar']);
-
-    // Get detailed information about the authenticated user.
-    $response = $this->get(
-      $this->tokenTestUrl,
-      [
-        'query' => ['_format' => 'json'],
-        'headers' => [
-          'Authorization' => 'Bearer ' . $access_token,
-        ],
-      ]
-    );
-    $parsed_response = Json::decode((string) $response->getBody());
+    $parsed_response = $this->debugToken($access_token);
     $this->assertEquals($this->user->id(), $parsed_response['id']);
-    $this->assertEquals(['foo', 'bar', 'authenticated', 'oof'], $parsed_response['roles']);
+    $this->assertEquals(['foo', 'bar', 'authenticated'], $parsed_response['roles']);
     $this->assertTrue($parsed_response['permissions']['view own simple_oauth entities']['access']);
     $this->assertTrue($parsed_response['permissions']['administer simple_oauth entities']['access']);
 
@@ -138,16 +140,7 @@ class RolesNegotiationFunctionalTest extends BrowserTestBase {
     // We have edited the user, but there was a non-expired existing token for
     // that user. Even though the TokenUser has the roles assigned, the
     // underlying user doesn't, so access should not be granted.
-    $response = $this->get(
-      $this->tokenTestUrl,
-      [
-        'query' => ['_format' => 'json'],
-        'headers' => [
-          'Authorization' => 'Bearer ' . $access_token,
-        ],
-      ]
-    );
-    $parsed_response = Json::decode((string) $response->getBody());
+    $parsed_response = $this->debugToken($access_token);
     // The token was successfully removed. The negotiated user is the anonymous
     // user.
     $this->assertEquals(0, $parsed_response['id']);
@@ -157,44 +150,39 @@ class RolesNegotiationFunctionalTest extends BrowserTestBase {
 
     // Request the access token again. This time the user doesn't have the role
     // requested at the time of generating the token.
-    $access_token = $this->getAccessToken(['foo', 'bar']);
-    $response = $this->get(
-      $this->tokenTestUrl,
-      [
-        'query' => ['_format' => 'json'],
-        'headers' => [
-          'Authorization' => 'Bearer ' . $access_token,
-        ],
-      ]
-    );
-    $parsed_response = Json::decode((string) $response->getBody());
+    $parsed_response = $this->debugToken($this->getAccessToken(['foo', 'bar']));
     // The negotiated user is the expected user.
     $this->assertEquals($this->user->id(), $parsed_response['id']);
-    $this->assertEquals(['foo', 'authenticated', 'oof'], $parsed_response['roles']);
+    $this->assertEquals(['foo', 'authenticated'], $parsed_response['roles']);
     $this->assertTrue($parsed_response['permissions']['view own simple_oauth entities']['access']);
     $this->assertFalse($parsed_response['permissions']['administer simple_oauth entities']['access']);
+
+    // Now delete the role from the consumer entity and see it go from the
+    // granted list.
+    $this->client->set('roles', [
+      ['target_id' => 'oof'],
+      ['target_id' => 'bar'],
+    ]);
+    $this->client->save();
+    // Request the access token again. This time the user doesn't have 'bar' and
+    // the consumer doesn't have 'foo'.
+    $parsed_response = $this->debugToken($this->getAccessToken(['foo', 'bar']));
+    // The negotiated user is the expected user.
+    $this->assertEquals($this->user->id(), $parsed_response['id']);
+    $this->assertEquals(['authenticated'], $parsed_response['roles']);
+    $this->assertFalse($parsed_response['permissions']['view own simple_oauth entities']['access']);
+    $this->assertFalse($parsed_response['permissions']['administer simple_oauth entities']['access']);
   }
 
   /**
-   * Test access to own unpublished node but with the role removed from client.
+   * Makes sure that the roles in the consumer but not in the user are skipped.
    */
   public function testRequestWithRoleRemovedFromClient() {
     $access_token = $this->getAccessToken(['oof']);
-
-    // Get detailed information about the authenticated user.
-    $response = $this->get(
-      $this->tokenTestUrl,
-      [
-        'query' => ['_format' => 'json'],
-        'headers' => [
-          'Authorization' => 'Bearer ' . $access_token,
-        ],
-      ]
-    );
-    $parsed_response = Json::decode((string) $response->getBody());
+    $parsed_response = $this->debugToken($access_token);
     $this->assertEquals($this->user->id(), $parsed_response['id']);
-    $this->assertEquals(['authenticated', 'oof'], $parsed_response['roles']);
-    $this->assertTrue($parsed_response['permissions']['delete own simple_oauth entities']['access']);
+    $this->assertEquals(['authenticated'], $parsed_response['roles']);
+    $this->assertFalse($parsed_response['permissions']['delete own simple_oauth entities']['access']);
 
     $this->client->set('roles', []);
     // After saving the client entity, the token should be deleted.
@@ -203,58 +191,43 @@ class RolesNegotiationFunctionalTest extends BrowserTestBase {
     // User should NOT have access to view own simple_oauth entities,
     // because the scope is indicated in the token request, but
     // missing from the client content entity.
-    $response = $this->get(
-      $this->tokenTestUrl,
-      [
-        'query' => ['_format' => 'json'],
-        'headers' => [
-          'Authorization' => 'Bearer ' . $access_token,
-        ],
-      ]
-    );
-    $parsed_response = Json::decode((string) $response->getBody());
+    $parsed_response = $this->debugToken($access_token);
     // The token was successfully removed. The negotiated user is the anonymous
     // user.
     $this->assertEquals(0, $parsed_response['id']);
     $this->assertEquals(['anonymous'], $parsed_response['roles']);
     $this->assertFalse($parsed_response['permissions']['view own simple_oauth entities']['access']);
-
-    $access_token = $this->getAccessToken(['oof']);
-    // Get detailed information about the authenticated user.
-    $response = $this->get(
-      $this->tokenTestUrl,
-      [
-        'query' => ['_format' => 'json'],
-        'headers' => [
-          'Authorization' => 'Bearer ' . $access_token,
-        ],
-      ]
-    );
-    $parsed_response = Json::decode((string) $response->getBody());
-    $this->assertEquals($this->user->id(), $parsed_response['id']);
-    $this->assertEquals(['authenticated'], $parsed_response['roles']);
-    $this->assertFalse($parsed_response['permissions']['delete own simple_oauth entities']['access']);
   }
 
   /**
-   * Test access to own unpublished node but with missing scope.
+   * Test access with anomalous scope situations..
    */
-  public function testRequestWithMissingScope() {
-    $access_token = $this->getAccessToken();
+  public function testRequestWithFailedScopes() {
+    $parsed_response = $this->debugToken($this->getAccessToken());
+    $this->assertEquals($this->user->id(), $parsed_response['id']);
+    $this->assertEquals(['authenticated'], $parsed_response['roles']);
 
-    $response = $this->get(
-      $this->tokenTestUrl,
-      [
-        'query' => ['_format' => 'json'],
-        'headers' => [
-          'Authorization' => 'Bearer ' . $access_token,
-        ],
-      ]
-    );
-    $parsed_response = Json::decode((string) $response->getBody());
+    // This scope is in the consumer, but not in the user list.
+    $parsed_response = $this->debugToken($this->getAccessToken(['rab']));
     $this->assertEquals($this->user->id(), $parsed_response['id']);
-    $this->assertEquals(['authenticated', 'oof'], $parsed_response['roles']);
-    $this->assertFalse($parsed_response['permissions']['view own simple_oauth entities']['access']);
+    $this->assertEquals(['authenticated'], $parsed_response['roles']);
+    $this->assertFalse($parsed_response['permissions']['update own simple_oauth entities']['access']);
+
+    // Add the 'rab' role to the whitelisted roles.
+    $this->client->set('roles', [
+      ['target_id' => 'oof'],
+      ['target_id' => 'foo'],
+      ['target_id' => 'bar'],
+      ['target_id' => 'rab'],
+    ]);
+    $this->client->save();
+    $parsed_response = $this->debugToken($this->getAccessToken(['rab']));
+    $this->assertEquals($this->user->id(), $parsed_response['id']);
+    $this->assertEquals(['rab', 'authenticated'], $parsed_response['roles']);
+    $this->assertTrue($parsed_response['permissions']['update own simple_oauth entities']['access']);
+
+    // Now try with an invalid scope.
+    $this->assertNull($this->getAccessToken(['FAIL']), $parsed_response);
   }
 
   /**
@@ -283,4 +256,26 @@ class RolesNegotiationFunctionalTest extends BrowserTestBase {
       : NULL;
   }
 
+  /**
+   * Executes a request against the token test URL to debug a token.
+   *
+   * @param string $access_token
+   *   The access token.
+   *
+   * @return array
+   *   The parsed response.
+   */
+  private function debugToken($access_token) {
+    $response = $this->get(
+      $this->tokenTestUrl,
+      [
+        'query' => ['_format' => 'json'],
+        'headers' => [
+          'Authorization' => 'Bearer ' . $access_token,
+        ],
+      ]
+    );
+    return Json::decode((string) $response->getBody());
+  }
+
 }
diff --git a/src/Authentication/TokenAuthUser.php b/src/Authentication/TokenAuthUser.php
index 235f4ed..38cd677 100644
--- a/src/Authentication/TokenAuthUser.php
+++ b/src/Authentication/TokenAuthUser.php
@@ -2,11 +2,14 @@
 
 namespace Drupal\simple_oauth\Authentication;
 
+use Drupal\consumers\Entity\Consumer;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\simple_oauth\Entity\Oauth2TokenInterface;
+use Drupal\simple_oauth\Repositories\ScopeRepository;
 use Drupal\user\Entity\User;
+use Drupal\user\RoleInterface;
 use Drupal\user\UserInterface;
 use League\OAuth2\Server\Exception\OAuthServerException;
 
@@ -77,9 +80,14 @@ class TokenAuthUser implements TokenAuthUserInterface {
    * {@inheritdoc}
    */
   public function getRoles($exclude_locked_roles = FALSE) {
-    return array_map(function ($item) {
+    $token_roles = array_map(function ($item) {
       return $item['target_id'];
     }, $this->token->get('scopes')->getValue());
+    return ScopeRepository::calculateAccessibleScopeIds(
+      $token_roles,
+      $this->subject,
+      $this->token->get('client')->entity
+    );
   }
 
   /**
diff --git a/src/Repositories/ScopeRepository.php b/src/Repositories/ScopeRepository.php
index da47796..27740fc 100644
--- a/src/Repositories/ScopeRepository.php
+++ b/src/Repositories/ScopeRepository.php
@@ -2,7 +2,9 @@
 
 namespace Drupal\simple_oauth\Repositories;
 
+use Drupal\consumers\Entity\Consumer;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Session\AccountInterface;
 use Drupal\user\RoleInterface;
 use League\OAuth2\Server\Entities\ClientEntityInterface;
 use League\OAuth2\Server\Entities\ScopeEntityInterface;
@@ -59,28 +61,53 @@ class ScopeRepository implements ScopeRepositoryInterface {
       ? $this->entityTypeManager->getStorage('user')->load($user_identifier)
       : $default_user;
     if (!$user) {
-      return [];
+      return [RoleInterface::ANONYMOUS_ID];
     }
 
-    $role_ids = $user->getRoles();
-    // Given a user, only allow the roles that the user already has, regardless
-    // of what has been requested.
-    $scopes = array_filter($scopes, function (ScopeEntityInterface $scope) use ($role_ids) {
-      return in_array($scope->getIdentifier(), $role_ids);
-    });
-
-    // Make sure that the Authenticated role is added as well.
-    $scopes = $this->addRoleToScopes($scopes, RoleInterface::AUTHENTICATED_ID);
-    // Make sure that the client roles are added to the scopes as well.
-    /** @var \Drupal\consumers\Entity\Consumer $client_drupal_entity */
-    $client_drupal_entity = $client_entity->getDrupalEntity();
-    $scopes = array_reduce($client_drupal_entity->get('roles')->getValue(), function ($scopes, $role_id) {
-      return $this->addRoleToScopes($scopes, $role_id['target_id']);
+    assert($client_entity instanceof \Drupal\simple_oauth\Entities\ClientEntityInterface);
+    $input_roles = array_map(function (ScopeEntityInterface $scope) {
+      return $scope->getIdentifier();
     }, $scopes);
-
+    $calculated_scope_ids = static::calculateAccessibleScopeIds(
+      $input_roles,
+      $user,
+      $client_entity->getDrupalEntity()
+    );
+    $scopes = array_reduce($calculated_scope_ids, [$this, 'addRoleToScopes'], []);
     return $scopes;
   }
 
+  /**
+   * Restricts the list of roles.
+   *
+   * We do so based on user input, client configuration and actual user roles.
+   *
+   * @param array $input_scope_ids
+   *   A list of user requested scope IDs.
+   * @param \Drupal\Core\Session\AccountInterface $user
+   *   The user that was actually authenticated.
+   * @param \Drupal\consumers\Entity\Consumer $consumer
+   *   The consumer entity associated to the client for this request.
+   *
+   * @return array
+   *   The list of scope IDs to be granted to the token / TokenUser.
+   */
+  public static function calculateAccessibleScopeIds(
+    array $input_scope_ids,
+    AccountInterface $user,
+    Consumer $consumer
+  ) {
+    $user_roles = $user->getRoles();
+    $client_roles = array_map(function ($item) {
+      return $item['target_id'];
+    }, $consumer->get('roles')->getValue());
+    $intersection = array_intersect($user_roles, $input_scope_ids, $client_roles);
+    return array_merge(
+      $intersection,
+      [$user->isAuthenticated() ? RoleInterface::AUTHENTICATED_ID : RoleInterface::ANONYMOUS_ID]
+    );
+  }
+
   /**
    * Build a scope entity.
    *
