diff --git a/apps/files_external/lib/AppInfo/Application.php b/apps/files_external/lib/AppInfo/Application.php
index e037b9b34e50dd866516e7180b72f2ea4f7d650e..f312e0651144277f55ff5034f0dd03587e9bc4f3 100644
--- a/apps/files_external/lib/AppInfo/Application.php
+++ b/apps/files_external/lib/AppInfo/Application.php
@@ -36,7 +36,8 @@ use \OCA\Files_External\Lib\Config\IBackendProvider;
 use \OCA\Files_External\Lib\Config\IAuthMechanismProvider;
 use OCA\Files_External\Lib\Auth\AmazonS3\AccessKey;
 use OCA\Files_External\Lib\Auth\OpenStack\Rackspace;
-use OCA\Files_External\Lib\Auth\OpenStack\OpenStack;
+use OCA\Files_External\Lib\Auth\OpenStack\OpenStackV2;
+use OCA\Files_External\Lib\Auth\OpenStack\OpenStackV3;
 use OCA\Files_External\Lib\Auth\PublicKey\RSA;
 use OCA\Files_External\Lib\Auth\OAuth2\OAuth2;
 use OCA\Files_External\Lib\Auth\OAuth1\OAuth1;
@@ -139,7 +140,8 @@ class Application extends App implements IBackendProvider, IAuthMechanismProvide
 			$container->query(RSA::class),
 
 			// AuthMechanism::SCHEME_OPENSTACK mechanisms
-			$container->query(OpenStack::class),
+			$container->query(OpenStackV2::class),
+			$container->query(OpenStackV3::class),
 			$container->query(Rackspace::class),
 
 			// Specialized mechanisms
diff --git a/apps/files_external/lib/Lib/Auth/OpenStack/OpenStack.php b/apps/files_external/lib/Lib/Auth/OpenStack/OpenStackV2.php
similarity index 94%
rename from apps/files_external/lib/Lib/Auth/OpenStack/OpenStack.php
rename to apps/files_external/lib/Lib/Auth/OpenStack/OpenStackV2.php
index ca1e0a08ae90bf5a528dcf3065ec2adce9d14c4d..f25918561f8de6ad428442268ca7dc5196c1bb1b 100644
--- a/apps/files_external/lib/Lib/Auth/OpenStack/OpenStack.php
+++ b/apps/files_external/lib/Lib/Auth/OpenStack/OpenStackV2.php
@@ -29,13 +29,13 @@ use \OCA\Files_External\Lib\Auth\AuthMechanism;
 /**
  * OpenStack Keystone authentication
  */
-class OpenStack extends AuthMechanism {
+class OpenStackV2 extends AuthMechanism {
 
 	public function __construct(IL10N $l) {
 		$this
 			->setIdentifier('openstack::openstack')
 			->setScheme(self::SCHEME_OPENSTACK)
-			->setText($l->t('OpenStack'))
+			->setText($l->t('OpenStack v2'))
 			->addParameters([
 				new DefinitionParameter('user', $l->t('Username')),
 				(new DefinitionParameter('password', $l->t('Password')))
diff --git a/apps/files_external/lib/Lib/Auth/OpenStack/OpenStackV3.php b/apps/files_external/lib/Lib/Auth/OpenStack/OpenStackV3.php
new file mode 100644
index 0000000000000000000000000000000000000000..adf6b8012a03b0da3a74e1de91e70f3a3b1feb0c
--- /dev/null
+++ b/apps/files_external/lib/Lib/Auth/OpenStack/OpenStackV3.php
@@ -0,0 +1,48 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files_External\Lib\Auth\OpenStack;
+
+use \OCP\IL10N;
+use \OCA\Files_External\Lib\DefinitionParameter;
+use \OCA\Files_External\Lib\Auth\AuthMechanism;
+
+/**
+ * OpenStack Keystone authentication
+ */
+class OpenStackV3 extends AuthMechanism {
+
+	public function __construct(IL10N $l) {
+		$this
+			->setIdentifier('openstack::openstackv3')
+			->setScheme(self::SCHEME_OPENSTACK)
+			->setText($l->t('OpenStack v3'))
+			->addParameters([
+				new DefinitionParameter('userid', $l->t('User Id')),
+				(new DefinitionParameter('password', $l->t('Password')))
+					->setType(DefinitionParameter::VALUE_PASSWORD),
+				new DefinitionParameter('url', $l->t('Identity endpoint URL'))
+			])
+		;
+	}
+
+}
diff --git a/apps/files_external/lib/Lib/Backend/Swift.php b/apps/files_external/lib/Lib/Backend/Swift.php
index f2b694362f4575dc7ad2eac91fa5b3e577f14945..72fc236bcdc3623310a50aa68bb947b7b70147fa 100644
--- a/apps/files_external/lib/Lib/Backend/Swift.php
+++ b/apps/files_external/lib/Lib/Backend/Swift.php
@@ -25,7 +25,8 @@ namespace OCA\Files_External\Lib\Backend;
 use \OCP\IL10N;
 use \OCA\Files_External\Lib\DefinitionParameter;
 use \OCA\Files_External\Lib\Auth\AuthMechanism;
-use \OCA\Files_External\Lib\Auth\OpenStack\OpenStack;
+use \OCA\Files_External\Service\BackendService;
+use \OCA\Files_External\Lib\Auth\OpenStack\OpenStackV2;
 use \OCA\Files_External\Lib\Auth\OpenStack\Rackspace;
 use \OCA\Files_External\Lib\LegacyDependencyCheckPolyfill;
 
@@ -33,7 +34,7 @@ class Swift extends Backend {
 
 	use LegacyDependencyCheckPolyfill;
 
-	public function __construct(IL10N $l, OpenStack $openstackAuth, Rackspace $rackspaceAuth) {
+	public function __construct(IL10N $l, OpenStackV2 $openstackAuth, Rackspace $rackspaceAuth) {
 		$this
 			->setIdentifier('swift')
 			->addIdentifierAlias('\OC\Files\Storage\Swift') // legacy compat
diff --git a/apps/files_external/lib/Lib/Storage/Swift.php b/apps/files_external/lib/Lib/Storage/Swift.php
index 051c65350d5b6a1f5b696bd9dec7260eef1ff562..2f8207cac4f8775428c4831a77f427152396fbe6 100644
--- a/apps/files_external/lib/Lib/Storage/Swift.php
+++ b/apps/files_external/lib/Lib/Storage/Swift.php
@@ -156,13 +156,14 @@ class Swift extends \OC\Files\Storage\Common {
 
 	public function __construct($params) {
 		if ((empty($params['key']) and empty($params['password']))
-			or empty($params['user']) or empty($params['bucket'])
+			or (empty($params['user']) && empty($params['userid'])) or empty($params['bucket'])
 			or empty($params['region'])
 		) {
 			throw new StorageBadConfigException("API Key or password, Username, Bucket and Region have to be configured.");
 		}
 
-		$this->id = 'swift::' . $params['user'] . md5($params['bucket']);
+		$user = isset($params['user']) ? $params['user'] : $params['userid'];
+		$this->id = 'swift::' . $user . md5($params['bucket']);
 
 		$bucketUrl = new Uri($params['bucket']);
 		if ($bucketUrl->getHost()) {
@@ -180,6 +181,13 @@ class Swift extends \OC\Files\Storage\Common {
 
 		$params['autocreate'] = true;
 
+		if (isset($params['userid'])) {
+			$params['user'] = [
+				'id' => $params['userid'],
+				'password' => $params['password']
+			];
+		}
+
 		$this->params = $params;
 		// FIXME: private class...
 		$this->objectCache = new \OC\Cache\CappedMemoryCache();
diff --git a/lib/private/Files/ObjectStore/SwiftFactory.php b/lib/private/Files/ObjectStore/SwiftFactory.php
index 0df6fb6efcd0cddb9153fe0af15c676f19c4407f..5a11d2c75920c25e200ba3cdf0450a3e22270dcd 100644
--- a/lib/private/Files/ObjectStore/SwiftFactory.php
+++ b/lib/private/Files/ObjectStore/SwiftFactory.php
@@ -31,8 +31,9 @@ use OCP\Files\StorageAuthException;
 use OCP\Files\StorageNotAvailableException;
 use OCP\ICache;
 use OpenStack\Common\Error\BadResponseError;
-use OpenStack\Identity\v2\Models\Token;
-use OpenStack\Identity\v2\Service;
+use OpenStack\Common\Auth\Token;
+use OpenStack\Identity\v2\Service as IdentityV2Service;
+use OpenStack\Identity\v3\Service as IdentityV3Service;
 use OpenStack\OpenStack;
 use OpenStack\Common\Transport\Utils as TransportUtils;
 use Psr\Http\Message\RequestInterface;
@@ -77,30 +78,49 @@ class SwiftFactory {
 			// should only be true for tests
 			$this->params['autocreate'] = false;
 		}
-		if (!isset($this->params['username']) && isset($this->params['user'])) {
-			$this->params['username'] = $this->params['user'];
+		if (isset($this->params['user']) && is_array($this->params['user'])) {
+			$userName = $this->params['user']['id'];
+		} else {
+			if (!isset($this->params['username']) && isset($this->params['user'])) {
+				$this->params['username'] = $this->params['user'];
+			}
+			$userName = $this->params['username'];
 		}
 		if (!isset($this->params['tenantName']) && isset($this->params['tenant'])) {
 			$this->params['tenantName'] = $this->params['tenant'];
 		}
 
-		$cacheKey = $this->params['username'] . '@' . $this->params['url'] . '/' . $this->params['bucket'];
+		$cacheKey = $userName . '@' . $this->params['url'] . '/' . $this->params['bucket'];
 		$token = $this->getCachedToken($cacheKey);
 		$hasToken = is_array($token) && (new \DateTimeImmutable($token['expires_at'])) > (new \DateTimeImmutable('now'));
 		if ($hasToken) {
 			$this->params['cachedToken'] = $token;
 		}
+
 		$httpClient = new Client([
 			'base_uri' => TransportUtils::normalizeUrl($this->params['url']),
 			'handler' => HandlerStack::create()
 		]);
 
-		$authService = Service::factory($httpClient);
+		if (isset($this->params['user']) && isset($this->params['user']['id'])) {
+			return $this->auth(IdentityV3Service::factory($httpClient), $cacheKey);
+		} else {
+			return $this->auth(IdentityV2Service::factory($httpClient), $cacheKey);
+		}
+	}
+
+	/**
+	 * @param IdentityV2Service|IdentityV3Service $authService
+	 * @param string $cacheKey
+	 * @return OpenStack
+	 * @throws StorageAuthException
+	 */
+	private function auth($authService, string $cacheKey) {
 		$this->params['identityService'] = $authService;
 		$this->params['authUrl'] = $this->params['url'];
 		$client = new OpenStack($this->params);
 
-		if (!$hasToken) {
+		if (!isset($this->params['cachedToken'])) {
 			try {
 				$token = $authService->generateToken($this->params);
 				$this->cacheToken($token, $cacheKey);