docs: def generate_access_token_from_refresh_token(request, client):
    """ Generates a new AccessToken from a request containing a refresh token.
  
    Read the specification: http://tools.ietf.org/html/rfc6749#section-6.
    """
    refresh_token_value = request.POST.get('refresh_token')
    if not refresh_token_value:
      raise InvalidRequest('no "refresh_token" provided')
  
    try:
      existing_access_token = AccessToken.objects.get(
          refresh_token=refresh_token_value,
          client=client)
    except AccessToken.DoesNotExist:
      raise InvalidGrant('"{}" is not a valid "refresh_token"'.format(
        refresh_token_value))
  
    if existing_access_token.invalidated:
      refresh_token_used_after_invalidation.send(
          sender='djoauth2',
          access_token=existing_access_token,
          request=request)
      raise InvalidGrant('"{}" is not a valid "refresh_token"'.format(
        refresh_token_value))
  
    if not existing_access_token.refreshable:
      raise InvalidGrant('access token is not refreshable')
  
    # The specification (http://tools.ietf.org/html/rfc6749#section-6) describes
    # the scope parameter as follows:
    #
    #     scope
    #           OPTIONAL.  The scope of the access request as described by
    #           Section 3.3.  The requested scope MUST NOT include any
    #           scope not originally granted by the resource owner, and if
    #           omitted is treated as equal to the scope originally granted
    #           by the resource owner.
    #
    # This opens the possibility that a Client might successfully request a
    # subset of the existing scopes, but later in the same section comes the
    # following:
    #
    #      If a new refresh token is issued, the refresh token scope MUST be
    #      identical to that of the refresh token included by the client in the
    #      request.
    #
    # Confusingly, http://tools.ietf.org/html/rfc6749#section-1.5 includes the
    # following:
    #
    #     Refresh tokens are credentials used to obtain access tokens.  Refresh
    #     tokens are issued to the client by the authorization server and are
    #     used to obtain a new access token when the current access token becomes
    #     invalid or expires, or to obtain additional access tokens with
    #     identical or narrower scope (access tokens may have a shorter lifetime
    #     and fewer permissions than authorized by the resource owner).
    #
    # This last section explicitly allows tokens with narrower scope than
    # originally granted, which is in direct contradiction with the directive
    # that the scope must be equivalent to that granted earlier.
    #
    # Because the specification seems to contradict itself, I tend towards
    # observing the stricter directive (not allowing a subset of scope,) even
    # though to me there seems to be no reason to disallow that feature. That
    # said, I'm not sure why a client would ever ask for less scope than
    # originally granted.
    scope_objects = existing_access_token.scopes.all()
    new_scope_names = request.POST.get('scope', '')
    if new_scope_names:
      new_scope_names = new_scope_names.split(' ')
      if not existing_access_token.has_scope(*new_scope_names):
        raise InvalidScope('requested scopes exceed initial grant')
  
      scope_objects = []
      for scope_name in new_scope_names:
        try:
          scope_objects.append(Scope.objects.get(name=scope_name))
        except Scope.DoesNotExist:
          raise InvalidScope('"{}" is not a valid scope'.format(scope_name))
  
    requested_scope_string = request.POST.get('scope', '')
    if requested_scope_string:
      requested_scope_names = set(requested_scope_string.split(' '))
      if not requested_scope_names == existing_access_token.get_scope_names_set():
        raise InvalidScope('requested scopes do not match initial grant')
  
  
    # The new AccessToken is only refreshable if at the time of refresh the
    # server is configured to create refreshable tokens by default. It DOES NOT
    # inherit the existing token's 'refreshability' automatically. No behavior is
    # described in the specification; I believe this to be a sane decision.
    new_access_token = AccessToken.objects.create(
        user=existing_access_token.user,
        client=existing_access_token.client)
    new_access_token.authorization_code = existing_access_token.authorization_code
    new_access_token.scopes = scope_objects
    new_access_token.save()
  
    existing_access_token.invalidate()
  
    return new_access_token