private function updateToken(RefreshTokenCredentials $refreshToken = null, $deviceCode = null)
    {
        $tokenData = null;

        // array of url parameters that will be sent in auth request
        $params = [];
        if ($refreshToken == null && !empty($deviceCode)) {
            $tokenData = $this->pollDeviceAccessToken($deviceCode);
            if ($tokenData === false) {
                return false;
            }
        } else {
            $this->setParams($params, $refreshToken == null ? $this->credentials : $refreshToken);

            try {
                $response = $this->post($params);
                $tokenData = MapperUtil::mapResponse($response);
            } catch (Exception $e) {
                throw($this->mapError($e, 'Error obtaining access token.'));
            }
        }

        if (empty($tokenData)) {
            throw new ClientError('Error obtaining access token.');
        }

        // Process the returned data, both expired_in and refresh_token are optional parameters
        $this->accessToken = ['access_token' => $tokenData->access_token,];
        if (isset($tokenData->expires_in)) {
            $this->accessToken['expires_in'] = time() + $tokenData->expires_in;
        }

        // Save access token to storage
        $this->storage->set('access_token', $this->accessToken);

        if (isset($tokenData->refresh_token)) {
            $this->refreshToken = $tokenData->refresh_token;
            // Save refresh token to storage
            $this->storage->set('refresh_token', $this->refreshToken);
        }
        // never delete existing refresh token

        return true;
    }