diff --git a/functionaltests/run_tests.sh b/functionaltests/run_tests.sh
index d616d36d..e27796c0 100755
--- a/functionaltests/run_tests.sh
+++ b/functionaltests/run_tests.sh
@@ -31,6 +31,8 @@ source openrc alt_demo alt_demo
 
 export OS_ALT_USERNAME=${OS_USERNAME}
 export OS_ALT_TENANT_NAME=${OS_TENANT_NAME}
+export OS_ALT_USER_DOMAIN_NAME=${OS_USER_DOMAIN_NAME}
+export OS_ALT_PROJECT_DOMAIN__NAME=${OS_PROJECT_DOMAIN_NAME}
 export OS_ALT_PASSWORD=${OS_PASSWORD}
 
 # Get admin credentials.
@@ -46,10 +48,14 @@ uri = $OS_AUTH_URL
 user = $OS_USERNAME
 tenant = $OS_TENANT_NAME
 pass = $OS_PASSWORD
+user_domain = $OS_USER_DOMAIN_NAME
+project_domain = $OS_PROJECT_DOMAIN_NAME
 [demo]
 user = $OS_ALT_USERNAME
 tenant = $OS_ALT_TENANT_NAME
 pass = $OS_ALT_PASSWORD
+user_domain = $OS_ALT_USER_DOMAIN_NAME
+project_domain = $OS_ALT_PROJECT_DOMAIN_NAME
 EOF
 
 cd $MISTRALCLIENT_DIR
diff --git a/mistralclient/api/base.py b/mistralclient/api/base.py
index d69f8819..c2b71b53 100644
--- a/mistralclient/api/base.py
+++ b/mistralclient/api/base.py
@@ -15,6 +15,8 @@
 import copy
 import json
 
+from keystoneauth1 import exceptions
+
 
 class Resource(object):
     resource_name = 'Something'
@@ -89,7 +91,10 @@ class ResourceManager(object):
         if dump_json:
             data = json.dumps(data)
 
-        resp = self.http_client.post(url, data)
+        try:
+            resp = self.http_client.post(url, data)
+        except exceptions.HttpError as ex:
+            self._raise_api_exception(ex.response)
 
         if resp.status_code != 201:
             self._raise_api_exception(resp)
@@ -100,7 +105,10 @@ class ResourceManager(object):
         if dump_json:
             data = json.dumps(data)
 
-        resp = self.http_client.put(url, data)
+        try:
+            resp = self.http_client.put(url, data)
+        except exceptions.HttpError as ex:
+            self._raise_api_exception(ex.response)
 
         if resp.status_code != 200:
             self._raise_api_exception(resp)
@@ -108,7 +116,10 @@ class ResourceManager(object):
         return self.resource_class(self, extract_json(resp, response_key))
 
     def _list(self, url, response_key=None):
-        resp = self.http_client.get(url)
+        try:
+            resp = self.http_client.get(url)
+        except exceptions.HttpError as ex:
+            self._raise_api_exception(ex.response)
 
         if resp.status_code != 200:
             self._raise_api_exception(resp)
@@ -117,7 +128,10 @@ class ResourceManager(object):
                 for resource_data in extract_json(resp, response_key)]
 
     def _get(self, url, response_key=None):
-        resp = self.http_client.get(url)
+        try:
+            resp = self.http_client.get(url)
+        except exceptions.HttpError as ex:
+            self._raise_api_exception(ex.response)
 
         if resp.status_code == 200:
             return self.resource_class(self, extract_json(resp, response_key))
@@ -125,7 +139,10 @@ class ResourceManager(object):
             self._raise_api_exception(resp)
 
     def _delete(self, url):
-        resp = self.http_client.delete(url)
+        try:
+            resp = self.http_client.delete(url)
+        except exceptions.HttpError as ex:
+            self._raise_api_exception(ex.response)
 
         if resp.status_code != 204:
             self._raise_api_exception(resp)
diff --git a/mistralclient/api/httpclient.py b/mistralclient/api/httpclient.py
index 83bdf28c..374bf8a5 100644
--- a/mistralclient/api/httpclient.py
+++ b/mistralclient/api/httpclient.py
@@ -15,15 +15,16 @@
 
 import base64
 import copy
+import logging
 import os
 
 from oslo_utils import importutils
-import requests
 
-import logging
+import requests
 
 
 AUTH_TOKEN = 'auth_token'
+SESSION = 'session'
 CACERT = 'cacert'
 CERT_FILE = 'cert'
 CERT_KEY = 'key'
@@ -33,6 +34,7 @@ USER_ID = 'user_id'
 REGION_NAME = 'region_name'
 
 TARGET_AUTH_TOKEN = 'target_auth_token'
+TARGET_SESSION = 'target_session'
 TARGET_AUTH_URI = 'target_auth_url'
 TARGET_PROJECT_ID = 'target_project_id'
 TARGET_USER_ID = 'target_user_id'
@@ -59,7 +61,9 @@ def log_request(func):
 class HTTPClient(object):
     def __init__(self, base_url, **kwargs):
         self.base_url = base_url
-        self.session = kwargs.pop('session', None)
+        self.session = kwargs.get('session')
+        if not self.session:
+            self.session = requests.Session()
         self.auth_token = kwargs.get(AUTH_TOKEN)
         self.project_id = kwargs.get(PROJECT_ID)
         self.user_id = kwargs.get(USER_ID)
@@ -68,6 +72,7 @@ class HTTPClient(object):
         self.region_name = kwargs.get(REGION_NAME)
         self.ssl_options = {}
 
+        self.target_session = kwargs.get(TARGET_SESSION)
         self.target_auth_token = kwargs.get(TARGET_AUTH_TOKEN)
         self.target_auth_uri = kwargs.get(TARGET_AUTH_URI)
         self.target_user_id = kwargs.get(TARGET_USER_ID)
@@ -80,11 +85,6 @@ class HTTPClient(object):
             TARGET_PROJECT_DOMAIN_NAME
         )
 
-        if self.session:
-            self.crud_provider = self.session
-        else:
-            self.crud_provider = requests
-
         if self.base_url.startswith('https'):
             if self.cacert and not os.path.exists(self.cacert):
                 raise ValueError('Unable to locate cacert file '
@@ -94,47 +94,42 @@ class HTTPClient(object):
                 LOG.warning('Client is set to not verify even though '
                             'cacert is provided.')
 
-            # These are already set by the session, so it's not needed
-            if not self.session:
-                if self.insecure:
-                    self.ssl_options['verify'] = False
+            if self.insecure:
+                self.ssl_options['verify'] = False
+            else:
+                if self.cacert:
+                    self.ssl_options['verify'] = self.cacert
                 else:
-                    if self.cacert:
-                        self.ssl_options['verify'] = self.cacert
-                    else:
-                        self.ssl_options['verify'] = True
+                    self.ssl_options['verify'] = True
 
-                self.ssl_options['cert'] = (
-                    kwargs.get(CERT_FILE),
-                    kwargs.get(CERT_KEY)
-                )
+            self.ssl_options['cert'] = (
+                kwargs.get(CERT_FILE),
+                kwargs.get(CERT_KEY)
+            )
 
     @log_request
     def get(self, url, headers=None):
         options = self._get_request_options('get', headers)
 
-        return self.crud_provider.get(self.base_url + url, **options)
+        return self.session.get(self.base_url + url, **options)
 
     @log_request
     def post(self, url, body, headers=None):
         options = self._get_request_options('post', headers)
 
-        return self.crud_provider.post(self.base_url + url,
-                                       data=body, **options)
+        return self.session.post(self.base_url + url, data=body, **options)
 
     @log_request
     def put(self, url, body, headers=None):
         options = self._get_request_options('put', headers)
 
-        return self.crud_provider.put(self.base_url + url,
-                                      data=body, **options)
+        return self.session.put(self.base_url + url, data=body, **options)
 
     @log_request
     def delete(self, url, headers=None):
         options = self._get_request_options('delete', headers)
 
-        return self.crud_provider.delete(self.base_url + url,
-                                         **options)
+        return self.session.delete(self.base_url + url, **options)
 
     def _get_request_options(self, method, headers):
         headers = self._update_headers(headers)
@@ -152,9 +147,9 @@ class HTTPClient(object):
         if not headers:
             headers = {}
 
-        if not self.session:
+        if isinstance(self.session, requests.Session):
             if self.auth_token:
-                headers['x-auth-token'] = self.auth_token
+                headers['X-Auth-Token'] = self.auth_token
 
             if self.project_id:
                 headers['X-Project-Id'] = self.project_id
diff --git a/mistralclient/api/v2/client.py b/mistralclient/api/v2/client.py
index c7dd0f06..123e88b5 100644
--- a/mistralclient/api/v2/client.py
+++ b/mistralclient/api/v2/client.py
@@ -54,6 +54,10 @@ class Client(object):
         auth_handler = auth.get_auth_handler(auth_type)
         auth_response = auth_handler.authenticate(req, session=session) or {}
 
+        # If the session was None and we're using keystone auth, it will be
+        # created by the auth_handler.
+        session = auth_response.pop('session', None)
+
         req.update(auth_response)
 
         mistral_url = auth_response.get('mistral_url') or mistral_url
diff --git a/mistralclient/auth/keystone.py b/mistralclient/auth/keystone.py
index 2d6f98f9..be105449 100644
--- a/mistralclient/auth/keystone.py
+++ b/mistralclient/auth/keystone.py
@@ -12,14 +12,19 @@
 #    See the License for the specific language governing permissions and
 #    limitations under the License.
 
-from keystoneclient import client
-from mistralclient import auth
+import logging
+
+import keystoneauth1.identity.generic as auth_plugin
+from keystoneauth1 import session as ks_session
+import mistralclient.api.httpclient as api
+from mistralclient import auth as mistral_auth
 from oslo_serialization import jsonutils
 
-import mistralclient.api.httpclient as api
+
+LOG = logging.getLogger(__name__)
 
 
-class KeystoneAuthHandler(auth.AuthHandler):
+class KeystoneAuthHandler(mistral_auth.AuthHandler):
 
     def authenticate(self, req, session=None):
         """Performs authentication via Keystone.
@@ -44,8 +49,8 @@ class KeystoneAuthHandler(auth.AuthHandler):
         project_name = req.get('project_name')
         project_id = req.get('project_id')
         region_name = req.get('region_name')
-        user_domain_name = req.get('user_domain_name', 'Default')
-        project_domain_name = req.get('project_domain_name', 'Default')
+        user_domain_name = req.get('user_domain_name')
+        project_domain_name = req.get('project_domain_name')
         cacert = req.get('cacert')
         insecure = req.get('insecure', False)
 
@@ -56,12 +61,8 @@ class KeystoneAuthHandler(auth.AuthHandler):
         target_auth_token = req.get('target_auth_token')
         target_project_name = req.get('target_project_name')
         target_project_id = req.get('target_project_id')
-        target_region_name = req.get('target_region_name')
-        target_user_domain_name = req.get('target_user_domain_name', 'Default')
-        target_project_domain_name = req.get(
-            'target_project_domain_name',
-            'Default'
-        )
+        target_user_domain_name = req.get('target_user_domain_name')
+        target_project_domain_name = req.get('target_project_domain_name')
         target_cacert = req.get('target_cacert')
         target_insecure = req.get('target_insecure')
 
@@ -77,33 +78,42 @@ class KeystoneAuthHandler(auth.AuthHandler):
 
         auth_response = {}
 
-        if session:
-            keystone = client.Client(session=session)
-        elif auth_url:
-            keystone = client.Client(
-                username=username,
-                user_id=user_id,
-                password=api_key,
-                token=auth_token,
-                tenant_id=project_id,
-                tenant_name=project_name,
-                auth_url=auth_url,
-                cacert=cacert,
-                insecure=insecure,
-                user_domain_name=user_domain_name,
-                project_domain_name=project_domain_name
-            )
-            keystone.authenticate()
-            auth_response.update({
-                api.AUTH_TOKEN: keystone.auth_token,
-                api.PROJECT_ID: keystone.project_id,
-                api.USER_ID: keystone.user_id,
-            })
+        if not session:
+            auth = None
+            if auth_token:
+                auth = auth_plugin.Token(
+                    auth_url=auth_url,
+                    token=auth_token,
+                    project_id=project_id,
+                    project_name=project_name,
+                    project_domain_name=project_domain_name,
+                    cacert=cacert,
+                    insecure=insecure)
+            elif api_key and (username or user_id):
+                auth = auth_plugin.Password(
+                    auth_url=auth_url,
+                    username=username,
+                    user_id=user_id,
+                    password=api_key,
+                    user_domain_name=user_domain_name,
+                    project_id=project_id,
+                    project_name=project_name,
+                    project_domain_name=project_domain_name)
 
-        if session or auth_url:
+            else:
+                # NOTE(jaosorior): We don't crash here cause it's needed for
+                # bash-completion to work. However, we do issue a warning to
+                # the user so if the request doesn't work. It's because of
+                # this.
+                LOG.warning("You must either provide a valid token or "
+                            "a password (api_key) and a user.")
+            if auth:
+                session = ks_session.Session(auth=auth)
+
+        if session:
             if not mistral_url:
                 try:
-                    mistral_url = keystone.service_catalog.url_for(
+                    mistral_url = session.get_endpoint(
                         service_type=service_type,
                         endpoint_type=endpoint_type,
                         region_name=region_name
@@ -112,35 +122,48 @@ class KeystoneAuthHandler(auth.AuthHandler):
                     mistral_url = None
 
             auth_response['mistral_url'] = mistral_url
+            auth_response['session'] = session
 
         if target_auth_url:
-            target_keystone = client.Client(
-                username=target_username,
-                user_id=target_user_id,
-                password=target_api_key,
-                token=target_auth_token,
-                tenant_id=target_project_id,
-                tenant_name=target_project_name,
-                project_id=target_project_id,
-                project_name=target_project_name,
-                auth_url=target_auth_url,
-                cacert=target_cacert,
-                insecure=target_insecure,
-                region_name=target_region_name,
-                user_domain_name=target_user_domain_name,
-                project_domain_name=target_project_domain_name
-            )
+            if target_auth_token:
+                target_auth = auth_plugin.Token(
+                    auth_url=target_auth_url,
+                    token=target_auth_token,
+                    project_id=target_project_id,
+                    project_name=target_project_name,
+                    project_domain_name=target_project_domain_name,
+                    cacert=target_cacert,
+                    insecure=target_insecure)
+            elif target_api_key and (target_username or target_user_id):
+                target_auth = auth_plugin.Password(
+                    auth_url=target_auth_url,
+                    username=target_username,
+                    user_id=target_user_id,
+                    password=target_api_key,
+                    user_domain_name=target_user_domain_name,
+                    project_id=target_project_id,
+                    project_name=target_project_name,
+                    project_domain_name=target_project_domain_name,
+                )
+            else:
+                raise RuntimeError("You must either provide a valid token or "
+                                   "a password (target_api_key) and a user.")
 
-            target_keystone.authenticate()
+            target_session = ks_session.Session(auth=target_auth)
+            target_auth_headers = target_session.get_auth_headers() or {}
+
+            # NOTE: (sharatss) The target_auth_token is required here so that
+            # it can be passed as a separate header later.
+            target_auth_token = target_auth_headers.get('X-Auth-Token')
 
             auth_response.update({
-                api.TARGET_AUTH_TOKEN: target_keystone.auth_token,
-                api.TARGET_PROJECT_ID: target_keystone.project_id,
-                api.TARGET_USER_ID: target_keystone.user_id,
+                api.TARGET_AUTH_TOKEN: target_auth_token,
+                api.TARGET_PROJECT_ID: target_session.get_project_id(),
+                api.TARGET_USER_ID: target_session.get_user_id(),
                 api.TARGET_AUTH_URI: target_auth_url,
                 api.TARGET_SERVICE_CATALOG: jsonutils.dumps(
-                    target_keystone.auth_ref
-                )
+                    target_auth.get_access(
+                        target_session)._data['access'])
             })
 
         return auth_response
diff --git a/mistralclient/shell.py b/mistralclient/shell.py
index 02353a27..d7a95095 100644
--- a/mistralclient/shell.py
+++ b/mistralclient/shell.py
@@ -285,8 +285,7 @@ class MistralShell(app.App):
             '--os-tenant-name',
             action='store',
             dest='tenant_name',
-            default=env('OS_TENANT_NAME', 'OS_PROJECT_NAME',
-                        default='Default'),
+            default=env('OS_TENANT_NAME', 'OS_PROJECT_NAME'),
             help='Authentication tenant name (Env: OS_TENANT_NAME'
                  ' or OS_PROJECT_NAME)'
         )
@@ -295,8 +294,7 @@ class MistralShell(app.App):
             '--os-project-name',
             action='store',
             dest='project_name',
-            default=env('OS_TENANT_NAME', 'OS_PROJECT_NAME',
-                        default='Default'),
+            default=env('OS_TENANT_NAME', 'OS_PROJECT_NAME'),
             help='Authentication project name (Env: OS_TENANT_NAME'
                  ' or OS_PROJECT_NAME), will use tenant_name if both'
                  ' tenant_name and project_name are set'
@@ -314,7 +312,7 @@ class MistralShell(app.App):
             '--os-project-domain-name',
             action='store',
             dest='project_domain_name',
-            default=env('OS_PROJECT_DOMAIN_NAME', default='Default'),
+            default=env('OS_PROJECT_DOMAIN_NAME'),
             help='Authentication project domain name'
                  ' (Env: OS_PROJECT_DOMAIN_NAME)'
         )
@@ -323,7 +321,7 @@ class MistralShell(app.App):
             '--os-user-domain-name',
             action='store',
             dest='user_domain_name',
-            default=env('OS_USER_DOMAIN_NAME', default='Default'),
+            default=env('OS_USER_DOMAIN_NAME'),
             help='Authentication user domain name'
                  ' (Env: OS_USER_DOMAIN_NAME)'
         )
@@ -435,7 +433,7 @@ class MistralShell(app.App):
             '--os-target-tenant-name',
             action='store',
             dest='target_tenant_name',
-            default=env('OS_TARGET_TENANT_NAME', 'Default'),
+            default=env('OS_TARGET_TENANT_NAME'),
             help='Authentication tenant name for target cloud'
                  ' (Env: OS_TARGET_TENANT_NAME)'
         )
diff --git a/mistralclient/tests/functional/cli/base.py b/mistralclient/tests/functional/cli/base.py
index 55df25d1..b870b151 100644
--- a/mistralclient/tests/functional/cli/base.py
+++ b/mistralclient/tests/functional/cli/base.py
@@ -39,10 +39,14 @@ def credentials(group='admin'):
         username = os.environ.get('OS_USERNAME')
         password = os.environ.get('OS_PASSWORD')
         tenant_name = os.environ.get('OS_TENANT_NAME')
+        user_domain = os.environ.get('OS_USER_DOMAIN_NAME')
+        project_domain = os.environ.get('OS_PROJECT_DOMAIN_NAME')
     else:
         username = os.environ.get('OS_ALT_USERNAME')
         password = os.environ.get('OS_ALT_PASSWORD')
         tenant_name = os.environ.get('OS_ALT_TENANT_NAME')
+        user_domain = os.environ.get('OS_ALT_USER_DOMAIN_NAME')
+        project_domain = os.environ.get('OS_ALT_PROJECT_DOMAIN_NAME')
 
     auth_url = os.environ.get('OS_AUTH_URL')
 
@@ -52,6 +56,8 @@ def credentials(group='admin'):
         password = password or config.get(group, 'pass')
         tenant_name = tenant_name or config.get(group, 'tenant')
         auth_url = auth_url or config.get('auth', 'uri')
+        user_domain = user_domain or config.get(group, 'user_domain')
+        project_domain = project_domain or config.get(group, 'project_domain')
 
     # TODO(ddeja): Default value of OS_AUTH_URL is to provide url to v3 API.
     # Since tempest openstack client doesn't properly handle it, we switch
@@ -77,6 +83,7 @@ class MistralCLIAuth(base.ClientTestBase):
             username=creds['username'],
             password=creds['password'],
             tenant_name=creds['tenant_name'],
+            project_name=creds['tenant_name'],
             uri=creds['auth_url'],
             cli_dir=CLI_DIR
         )
@@ -130,6 +137,7 @@ class MistralCLIAltAuth(base.ClientTestBase):
         clients = base.CLIClient(
             username=creds['username'],
             password=creds['password'],
+            project_name=creds['tenant_name'],
             tenant_name=creds['tenant_name'],
             uri=creds['auth_url'],
             cli_dir=CLI_DIR
diff --git a/mistralclient/tests/functional/cli/v2/cli_multi_tenancy_tests.py b/mistralclient/tests/functional/cli/v2/cli_multi_tenancy_tests.py
index 70971e74..1fe22bcf 100644
--- a/mistralclient/tests/functional/cli/v2/cli_multi_tenancy_tests.py
+++ b/mistralclient/tests/functional/cli/v2/cli_multi_tenancy_tests.py
@@ -192,7 +192,8 @@ class WorkflowSharingCLITests(base_v2.MistralClientTestBase):
 
         self.assertEqual('pending', status)
 
-        cmd_param = '%s workflow --status %s' % (self.wf[0]["ID"], new_status)
+        cmd_param = '%s workflow --status %s --member-id %s' % (
+            self.wf[0]["ID"], new_status, self.get_project_id("demo"))
         member = self.mistral_alt_user("member-update", params=cmd_param)
         status = self.get_field_value(member, 'Status')
 
diff --git a/mistralclient/tests/unit/test_client.py b/mistralclient/tests/unit/test_client.py
index 7348e885..ebeadf6b 100644
--- a/mistralclient/tests/unit/test_client.py
+++ b/mistralclient/tests/unit/test_client.py
@@ -35,26 +35,26 @@ PROFILER_HMAC_KEY = 'SECRET_HMAC_KEY'
 class BaseClientTests(base.BaseTestCase):
 
     @staticmethod
-    def setup_keystone_mock(keystone_client_mock):
-        keystone_client_instance = keystone_client_mock.return_value
+    def setup_keystone_mock(session_mock):
+        keystone_client_instance = session_mock.return_value
         keystone_client_instance.auth_token = uuidutils.generate_uuid()
         keystone_client_instance.project_id = uuidutils.generate_uuid()
         keystone_client_instance.user_id = uuidutils.generate_uuid()
         keystone_client_instance.auth_ref = str(json.dumps({}))
         return keystone_client_instance
 
-    @mock.patch('keystoneclient.client.Client')
-    def test_mistral_url_from_catalog_v2(self, keystone_client_mock):
-        keystone_client_instance = self.setup_keystone_mock(
-            keystone_client_mock
-        )
+    @mock.patch('keystoneauth1.session.Session')
+    def test_mistral_url_from_catalog_v2(self, session_mock):
+        session = mock.Mock()
+        session_mock.side_effect = [session]
 
-        url_for = mock.Mock(return_value='http://mistral_host:8989/v2')
-        keystone_client_instance.service_catalog.url_for = url_for
+        get_endpoint = mock.Mock(return_value='http://mistral_host:8989/v2')
+        session.get_endpoint = get_endpoint
 
         mistralclient = client.client(
             username='mistral',
             project_name='mistral',
+            api_key='password',
             auth_url=AUTH_HTTP_URL_v2_0,
             service_type='workflowv2'
         )
@@ -64,19 +64,20 @@ class BaseClientTests(base.BaseTestCase):
             mistralclient.actions.http_client.base_url
         )
 
-    @mock.patch('keystoneclient.client.Client')
-    def test_mistral_url_from_catalog(self, keystone_client_mock):
-        keystone_client_instance = self.setup_keystone_mock(
-            keystone_client_mock
-        )
+    @mock.patch('keystoneauth1.session.Session')
+    def test_mistral_url_from_catalog(self, session_mock):
+        session = mock.Mock()
+        session_mock.side_effect = [session]
 
-        url_for = mock.Mock(return_value='http://mistral_host:8989/v2')
-
-        keystone_client_instance.service_catalog.url_for = url_for
+        get_endpoint = mock.Mock(return_value='http://mistral_host:8989/v2')
+        session.get_endpoint = get_endpoint
 
         mistralclient = client.client(
             username='mistral',
             project_name='mistral',
+            api_key='password',
+            user_domain_name='Default',
+            project_domain_name='Default',
             auth_url=AUTH_HTTP_URL_v3,
             service_type='workflowv2'
         )
@@ -86,82 +87,97 @@ class BaseClientTests(base.BaseTestCase):
             mistralclient.actions.http_client.base_url
         )
 
-    @mock.patch('keystoneclient.client.Client')
+    @mock.patch('keystoneauth1.session.Session')
     @mock.patch('mistralclient.api.httpclient.HTTPClient')
-    def test_mistral_url_default(self, http_client_mock, keystone_client_mock):
-        keystone_client_instance = self.setup_keystone_mock(
-            keystone_client_mock
-        )
+    def test_mistral_url_default(self, http_client_mock, session_mock):
+        session = mock.Mock()
+        session_mock.side_effect = [session]
 
-        url_for = mock.Mock(side_effect=Exception)
-        keystone_client_instance.service_catalog.url_for = url_for
+        get_endpoint = mock.Mock(side_effect=Exception)
+        session.get_endpoint = get_endpoint
 
         client.client(
             username='mistral',
             project_name='mistral',
+            api_key='password',
+            user_domain_name='Default',
+            project_domain_name='Default',
             auth_url=AUTH_HTTP_URL_v3
         )
 
         self.assertTrue(http_client_mock.called)
         mistral_url_for_http = http_client_mock.call_args[0][0]
-        kwargs = http_client_mock.call_args[1]
         self.assertEqual(MISTRAL_HTTP_URL, mistral_url_for_http)
-        self.assertEqual(
-            keystone_client_instance.auth_token, kwargs['auth_token']
-        )
-        self.assertEqual(
-            keystone_client_instance.project_id, kwargs['project_id']
-        )
-        self.assertEqual(
-            keystone_client_instance.user_id, kwargs['user_id']
-        )
 
-    @mock.patch('keystoneclient.client.Client')
+    @mock.patch('keystoneauth1.identity.generic.Password')
+    @mock.patch('keystoneauth1.session.Session')
     @mock.patch('mistralclient.api.httpclient.HTTPClient')
     def test_target_parameters_processed(
         self,
         http_client_mock,
-        keystone_client_mock
+        session_mock,
+        password_mock
     ):
-        keystone_client_instance = self.setup_keystone_mock(
-            keystone_client_mock
-        )
 
-        url_for = mock.Mock(return_value='http://mistral_host:8989/v2')
-        keystone_client_instance.service_catalog.url_for = url_for
+        session = mock.MagicMock()
+        target_session = mock.MagicMock()
+        session_mock.side_effect = [session, target_session]
+        auth = mock.MagicMock()
+        password_mock.side_effect = [auth, auth]
+
+        get_endpoint = mock.Mock(return_value='http://mistral_host:8989/v2')
+        session.get_endpoint = get_endpoint
+
+        target_session.get_project_id = mock.Mock(return_value='projectid')
+        target_session.get_user_id = mock.Mock(return_value='userid')
+        target_session.get_auth_headers = mock.Mock(return_value={
+            'X-Auth-Token': 'authtoken'
+        })
+
+        mock_access = mock.MagicMock()
+        mock_catalog = mock.MagicMock()
+        mock_catalog.catalog = {}
+        mock_access.service_catalog = mock_catalog
+        auth.get_access = mock.Mock(return_value=mock_access)
 
         client.client(
+            username='user',
+            api_key='password',
+            user_domain_name='Default',
+            project_domain_name='Default',
             target_username='tmistral',
             target_project_name='tmistralp',
             target_auth_url=AUTH_HTTP_URL_v3,
+            target_api_key='tpassword',
+            target_user_domain_name='Default',
+            target_project_domain_name='Default',
             target_region_name='tregion'
         )
 
         self.assertTrue(http_client_mock.called)
         mistral_url_for_http = http_client_mock.call_args[0][0]
         kwargs = http_client_mock.call_args[1]
-        self.assertEqual(MISTRAL_HTTP_URL, mistral_url_for_http)
+        self.assertEqual('http://mistral_host:8989/v2', mistral_url_for_http)
 
         expected_values = {
-            'target_project_id': keystone_client_instance.project_id,
-            'target_auth_token': keystone_client_instance.auth_token,
-            'target_user_id': keystone_client_instance.user_id,
+            'target_project_id': 'projectid',
+            'target_auth_token': 'authtoken',
+            'target_user_id': 'userid',
             'target_auth_url': AUTH_HTTP_URL_v3,
             'target_project_name': 'tmistralp',
             'target_username': 'tmistral',
             'target_region_name': 'tregion',
-            'target_service_catalog': '"{}"'
+            'target_service_catalog': "{}"
         }
 
         for key in expected_values:
             self.assertEqual(expected_values[key], kwargs[key])
 
-    @mock.patch('keystoneclient.client.Client')
+    @mock.patch('keystoneauth1.session.Session')
     @mock.patch('mistralclient.api.httpclient.HTTPClient')
-    def test_mistral_url_https_insecure(self, http_client_mock,
-                                        keystone_client_mock):
+    def test_mistral_url_https_insecure(self, http_client_mock, session_mock):
         keystone_client_instance = self.setup_keystone_mock(  # noqa
-            keystone_client_mock
+            session_mock
         )
 
         expected_args = (
@@ -172,6 +188,9 @@ class BaseClientTests(base.BaseTestCase):
             mistral_url=MISTRAL_HTTPS_URL,
             username='mistral',
             project_name='mistral',
+            api_key='password',
+            user_domain_name='Default',
+            project_domain_name='Default',
             auth_url=AUTH_HTTP_URL_v3,
             cacert=None,
             insecure=True
@@ -181,14 +200,13 @@ class BaseClientTests(base.BaseTestCase):
         self.assertEqual(http_client_mock.call_args[0], expected_args)
         self.assertEqual(http_client_mock.call_args[1]['insecure'], True)
 
-    @mock.patch('keystoneclient.client.Client')
+    @mock.patch('keystoneauth1.session.Session')
     @mock.patch('mistralclient.api.httpclient.HTTPClient')
-    def test_mistral_url_https_secure(self, http_client_mock,
-                                      keystone_client_mock):
+    def test_mistral_url_https_secure(self, http_client_mock, session_mock):
         fd, cert_path = tempfile.mkstemp(suffix='.pem')
 
         keystone_client_instance = self.setup_keystone_mock(  # noqa
-            keystone_client_mock
+            session_mock
         )
 
         expected_args = (
@@ -200,6 +218,9 @@ class BaseClientTests(base.BaseTestCase):
                 mistral_url=MISTRAL_HTTPS_URL,
                 username='mistral',
                 project_name='mistral',
+                api_key='password',
+                user_domain_name='Default',
+                project_domain_name='Default',
                 auth_url=AUTH_HTTP_URL_v3,
                 cacert=cert_path,
                 insecure=False
@@ -212,10 +233,10 @@ class BaseClientTests(base.BaseTestCase):
         self.assertEqual(http_client_mock.call_args[0], expected_args)
         self.assertEqual(http_client_mock.call_args[1]['cacert'], cert_path)
 
-    @mock.patch('keystoneclient.client.Client')
-    def test_mistral_url_https_bad_cacert(self, keystone_client_mock):
+    @mock.patch('keystoneauth1.session.Session')
+    def test_mistral_url_https_bad_cacert(self, session_mock):
         keystone_client_instance = self.setup_keystone_mock(  # noqa
-            keystone_client_mock
+            session_mock
         )
 
         self.assertRaises(
@@ -224,19 +245,22 @@ class BaseClientTests(base.BaseTestCase):
             mistral_url=MISTRAL_HTTPS_URL,
             username='mistral',
             project_name='mistral',
+            api_key='password',
+            user_domain_name='Default',
+            project_domain_name='Default',
             auth_url=AUTH_HTTP_URL_v3,
             cacert='/path/to/foobar',
             insecure=False
         )
 
     @mock.patch('logging.Logger.warning')
-    @mock.patch('keystoneclient.client.Client')
-    def test_mistral_url_https_bad_insecure(self, keystone_client_mock,
+    @mock.patch('keystoneauth1.session.Session')
+    def test_mistral_url_https_bad_insecure(self, session_mock,
                                             log_warning_mock):
         fd, path = tempfile.mkstemp(suffix='.pem')
 
         keystone_client_instance = self.setup_keystone_mock(
-            keystone_client_mock
+            session_mock
         )
 
         try:
@@ -244,6 +268,9 @@ class BaseClientTests(base.BaseTestCase):
                 mistral_url=MISTRAL_HTTPS_URL,
                 user_id=keystone_client_instance.user_id,
                 project_id=keystone_client_instance.project_id,
+                api_key='password',
+                user_domain_name='Default',
+                project_domain_name='Default',
                 auth_url=AUTH_HTTP_URL_v3,
                 cacert=path,
                 insecure=True
@@ -254,17 +281,19 @@ class BaseClientTests(base.BaseTestCase):
 
         self.assertTrue(log_warning_mock.called)
 
-    @mock.patch('keystoneclient.client.Client')
+    @mock.patch('keystoneauth1.session.Session')
     @mock.patch('mistralclient.api.httpclient.HTTPClient')
-    def test_mistral_profile_enabled(self, http_client_mock,
-                                     keystone_client_mock):
+    def test_mistral_profile_enabled(self, http_client_mock, session_mock):
         keystone_client_instance = self.setup_keystone_mock(  # noqa
-            keystone_client_mock
+            session_mock
         )
 
         client.client(
             username='mistral',
             project_name='mistral',
+            api_key='password',
+            user_domain_name='Default',
+            project_domain_name='Default',
             auth_url=AUTH_HTTP_URL_v3,
             profile=PROFILER_HMAC_KEY
         )
diff --git a/mistralclient/tests/unit/test_httpclient.py b/mistralclient/tests/unit/test_httpclient.py
index 68806cdd..297ccb6f 100644
--- a/mistralclient/tests/unit/test_httpclient.py
+++ b/mistralclient/tests/unit/test_httpclient.py
@@ -38,7 +38,7 @@ PROFILER_HMAC_KEY = 'SECRET_HMAC_KEY'
 PROFILER_TRACE_ID = uuidutils.generate_uuid()
 
 EXPECTED_AUTH_HEADERS = {
-    'x-auth-token': AUTH_TOKEN,
+    'X-Auth-Token': AUTH_TOKEN,
     'X-Project-Id': PROJECT_ID,
     'X-User-Id': USER_ID,
     'X-Region-Name': REGION_NAME
diff --git a/releasenotes/notes/remove-keystoneclient-dependency-f2981f29e6673f71.yaml b/releasenotes/notes/remove-keystoneclient-dependency-f2981f29e6673f71.yaml
new file mode 100644
index 00000000..1ee1b64e
--- /dev/null
+++ b/releasenotes/notes/remove-keystoneclient-dependency-f2981f29e6673f71.yaml
@@ -0,0 +1,6 @@
+---
+other:
+  - The dependency to python-keystoneclient was removed. Relying solely on
+    keystoneauth1.
+  - The user has to set the "OS_USER_DOMAIN_NAME" and "OS_PROJECT_DOMAIN_NAME"
+    explicitly if keystone v3 version is being used.
diff --git a/requirements.txt b/requirements.txt
index 4bb4c293..0be12617 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,7 +6,7 @@ osc-lib>=1.7.0 # Apache-2.0
 oslo.utils>=3.20.0 # Apache-2.0
 oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0
 pbr!=2.1.0,>=2.0.0 # Apache-2.0
-python-keystoneclient>=3.8.0 # Apache-2.0
+keystoneauth1>=3.1.0  # Apache-2.0
 PyYAML>=3.10.0 # MIT
 requests>=2.14.2 # Apache-2.0
 six>=1.9.0 # MIT