diff --git a/apps/dav/appinfo/v1/publicwebdav.php b/apps/dav/appinfo/v1/publicwebdav.php
index 261a4d4b96de5fa0cbcebe7737ce932db6ad26f3..2202cbb977cab73b7813121c1c8e11c9a0265562 100644
--- a/apps/dav/appinfo/v1/publicwebdav.php
+++ b/apps/dav/appinfo/v1/publicwebdav.php
@@ -57,7 +57,7 @@ $linkCheckPlugin = new \OCA\DAV\Files\Sharing\PublicLinkCheckPlugin();
 
 $server = $serverFactory->createServer($baseuri, $requestUri, $authBackend, function (\Sabre\DAV\Server $server) use ($authBackend, $linkCheckPlugin) {
 	$isAjax = (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest');
-	$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application('federatedfilesharing');
+	$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application();
 	$federatedShareProvider = $federatedSharingApp->getFederatedShareProvider();
 	if ($federatedShareProvider->isOutgoingServer2serverShareEnabled() === false && !$isAjax) {
 		// this is what is thrown when trying to access a non-existing share
diff --git a/apps/federatedfilesharing/appinfo/app.php b/apps/federatedfilesharing/appinfo/app.php
index 5891b9cbbc1e665e75ac5024b041a5a0a19158de..e6fbe615e7f93f8c804aaedfdc4a81ab2ad7cb25 100644
--- a/apps/federatedfilesharing/appinfo/app.php
+++ b/apps/federatedfilesharing/appinfo/app.php
@@ -20,11 +20,11 @@
  *
  */
 
-$app = new \OCA\FederatedFileSharing\AppInfo\Application('federatedfilesharing');
-
 use OCA\FederatedFileSharing\Notifier;
 
+$app = new \OCA\FederatedFileSharing\AppInfo\Application();
 $l = \OC::$server->getL10N('files_sharing');
+$eventDispatcher = \OC::$server->getEventDispatcher();
 
 $app->registerSettings();
 
@@ -39,3 +39,14 @@ $manager->registerNotifier(function() {
 		'name' => $l->t('Federated sharing'),
 	];
 });
+
+$federatedShareProvider = $app->getFederatedShareProvider();
+
+$eventDispatcher->addListener(
+	'OCA\Files::loadAdditionalScripts',
+	function() use ($federatedShareProvider) {
+		if ($federatedShareProvider->isIncomingServer2serverShareEnabled()) {
+			\OCP\Util::addScript('federatedfilesharing', 'external');
+		}
+	}
+);
diff --git a/apps/federatedfilesharing/appinfo/routes.php b/apps/federatedfilesharing/appinfo/routes.php
new file mode 100644
index 0000000000000000000000000000000000000000..ec7b662686ff5520d422443fa31f33a30d97755c
--- /dev/null
+++ b/apps/federatedfilesharing/appinfo/routes.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
+ *
+ * @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/>.
+ *
+ */
+
+return [
+	'routes' => [
+		['name' => 'MountPublicLink#createFederatedShare', 'url' => '/createFederatedShare', 'verb' => 'POST'],
+		['name' => 'MountPublicLink#askForFederatedShare', 'url' => '/askForFederatedShare', 'verb' => 'POST'],
+	]
+];
diff --git a/apps/files_sharing/js/external.js b/apps/federatedfilesharing/js/external.js
similarity index 87%
rename from apps/files_sharing/js/external.js
rename to apps/federatedfilesharing/js/external.js
index 0ca8213168e45bc6ec979b35c08b1b887bb0ac49..1daecd2e744bca8709566d0c554766b7b66d0aba 100644
--- a/apps/files_sharing/js/external.js
+++ b/apps/federatedfilesharing/js/external.js
@@ -99,20 +99,29 @@
 				var callbackAddShare = function(result, share) {
 					var password = share.password || '';
 					if (result) {
-						//$.post(OC.generateUrl('/apps/files_sharing/api/externalShares'), {id: share.id});
-						$.post(OC.generateUrl('apps/files_sharing/external'), {
-							remote: share.remote,
-							token: share.token,
-							owner: share.owner,
-							ownerDisplayName: share.ownerDisplayName || share.owner,
-							name: share.name,
-							password: password}, function(result) {
-							if (result.status === 'error') {
-								OC.Notification.showTemporary(result.data.message);
-							} else {
-								fileList.reload();
+						$.post(
+							OC.generateUrl('apps/federatedfilesharing/askForFederatedShare'),
+							{
+								remote: share.remote,
+								token: share.token,
+								owner: share.owner,
+								ownerDisplayName: share.ownerDisplayName || share.owner,
+								name: share.name,
+								password: password
 							}
-						});
+						).done(
+							function(data) {
+								if (data.hasOwnProperty('legacyMount')) {
+									fileList.reload();
+								} else {
+									OC.Notification.showTemporary(data.message);
+								}
+						}
+						).fail(
+							function(data) {
+								OC.Notification.showTemporary(JSON.parse(data.responseText).message);
+							}
+						);
 					}
 				};
 
@@ -166,4 +175,3 @@
 })();
 
 OC.Plugins.register('OCA.Files.App', OCA.Sharing.ExternalShareDialogPlugin);
-
diff --git a/apps/federatedfilesharing/lib/AppInfo/Application.php b/apps/federatedfilesharing/lib/AppInfo/Application.php
index 4faebea7b0ae72d54deb8d18b6d4212bd221cef8..ea5018e6a903055bff7c9254f4eb71b91a164a08 100644
--- a/apps/federatedfilesharing/lib/AppInfo/Application.php
+++ b/apps/federatedfilesharing/lib/AppInfo/Application.php
@@ -31,6 +31,10 @@ class Application extends App {
 	/** @var FederatedShareProvider */
 	protected $federatedShareProvider;
 
+	public function __construct() {
+		parent::__construct('federatedfilesharing');
+	}
+
 	/**
 	 * register personal and admin settings page
 	 */
diff --git a/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php b/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php
new file mode 100644
index 0000000000000000000000000000000000000000..3e61d355b63fcf36593c0c229a3932c4ce7ac471
--- /dev/null
+++ b/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php
@@ -0,0 +1,324 @@
+<?php
+/**
+ * @author Björn Schießle <bjoern@schiessle.org>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, Björn Schießle <bjoern@schiessle.org>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\FederatedFileSharing\Controller;
+
+use OC\HintException;
+use OCA\FederatedFileSharing\AddressHandler;
+use OCA\FederatedFileSharing\FederatedShareProvider;
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\Http\Client\IClientService;
+use OCP\IL10N;
+use OCP\IRequest;
+use OCP\ISession;
+use OCP\IUserSession;
+use OCP\Share\IManager;
+
+/**
+ * Class MountPublicLinkController
+ *
+ * convert public links to federated shares
+ *
+ * @package OCA\FederatedFileSharing\Controller
+ */
+class MountPublicLinkController extends Controller {
+
+	/** @var FederatedShareProvider */
+	private $federatedShareProvider;
+
+	/** @var AddressHandler */
+	private $addressHandler;
+
+	/** @var IManager  */
+	private $shareManager;
+
+	/** @var  ISession */
+	private $session;
+
+	/** @var IL10N */
+	private $l;
+
+	/** @var IUserSession */
+	private $userSession;
+
+	/** @var IClientService */
+	private $clientService;
+
+	/**
+	 * MountPublicLinkController constructor.
+	 *
+	 * @param string $appName
+	 * @param IRequest $request
+	 * @param FederatedShareProvider $federatedShareProvider
+	 * @param IManager $shareManager
+	 * @param AddressHandler $addressHandler
+	 * @param ISession $session
+	 * @param IL10N $l
+	 * @param IUserSession $userSession
+	 * @param IClientService $clientService
+	 */
+	public function __construct($appName,
+								IRequest $request,
+								FederatedShareProvider $federatedShareProvider,
+								IManager $shareManager,
+								AddressHandler $addressHandler,
+								ISession $session,
+								IL10N $l,
+								IUserSession $userSession,
+								IClientService $clientService
+	) {
+		parent::__construct($appName, $request);
+
+		$this->federatedShareProvider = $federatedShareProvider;
+		$this->shareManager = $shareManager;
+		$this->addressHandler = $addressHandler;
+		$this->session = $session;
+		$this->l = $l;
+		$this->userSession = $userSession;
+		$this->clientService = $clientService;
+	}
+
+	/**
+	 * send federated share to a user of a public link
+	 *
+	 * @NoCSRFRequired
+	 * @PublicPage
+	 *
+	 * @param string $shareWith
+	 * @param string $token
+	 * @param string $password
+	 * @return JSONResponse
+	 */
+	public function createFederatedShare($shareWith, $token, $password = '') {
+
+		if (!$this->federatedShareProvider->isOutgoingServer2serverShareEnabled()) {
+			return new JSONResponse(
+				['message' => 'This server doesn\'t support outgoing federated shares'],
+				Http::STATUS_BAD_REQUEST
+			);
+		}
+
+		try {
+			list(, $server) = $this->addressHandler->splitUserRemote($shareWith);
+			$share = $this->shareManager->getShareByToken($token);
+		} catch (HintException $e) {
+			return new JSONResponse(['message' => $e->getHint()], Http::STATUS_BAD_REQUEST);
+		}
+
+		// make sure that user is authenticated in case of a password protected link
+		$storedPassword = $share->getPassword();
+		$authenticated = $this->session->get('public_link_authenticated') === $share->getId() ||
+			$this->shareManager->checkPassword($share, $password);
+		if (!empty($storedPassword) && !$authenticated ) {
+			return new JSONResponse(
+				['message' => 'No permission to access the share'],
+				Http::STATUS_BAD_REQUEST
+			);
+		}
+
+		$share->setSharedWith($shareWith);
+
+		try {
+			$this->federatedShareProvider->create($share);
+		} catch (\Exception $e) {
+			return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
+		}
+
+		return new JSONResponse(['remoteUrl' => $server]);
+	}
+
+	/**
+	 * ask other server to get a federated share
+	 *
+	 * @NoAdminRequired
+	 *
+	 * @param string $token
+	 * @param string $remote
+	 * @param string $password
+	 * @param string $owner (only for legacy reasons, can be removed with legacyMountPublicLink())
+	 * @param string $ownerDisplayName (only for legacy reasons, can be removed with legacyMountPublicLink())
+	 * @param string $name (only for legacy reasons, can be removed with legacyMountPublicLink())
+	 * @return JSONResponse
+	 */
+	public function askForFederatedShare($token, $remote, $password = '', $owner = '', $ownerDisplayName = '', $name = '') {
+		// check if server admin allows to mount public links from other servers
+		if ($this->federatedShareProvider->isIncomingServer2serverShareEnabled() === false) {
+			return new JSONResponse(['message' => $this->l->t('Server to server sharing is not enabled on this server')], Http::STATUS_BAD_REQUEST);
+		}
+
+		$shareWith = $this->userSession->getUser()->getUID() . '@' . $this->addressHandler->generateRemoteURL();
+
+		$httpClient = $this->clientService->newClient();
+
+		try {
+			$response = $httpClient->post($remote . '/index.php/apps/federatedfilesharing/createFederatedShare',
+				[
+					'body' =>
+						[
+							'token' => $token,
+							'shareWith' => rtrim($shareWith, '/'),
+							'password' => $password
+						],
+					'connect_timeout' => 10,
+				]
+			);
+		} catch (\Exception $e) {
+			if (empty($password)) {
+				$message = $this->l->t("Couldn't establish a federated share.");
+			} else {
+				$message = $this->l->t("Couldn't establish a federated share, maybe the password was wrong.");
+			}
+			return new JSONResponse(['message' => $message], Http::STATUS_BAD_REQUEST);
+		}
+
+		$body = $response->getBody();
+		$result = json_decode($body, true);
+
+		if (is_array($result) && isset($result['remoteUrl'])) {
+			return new JSONResponse(['message' => $this->l->t('Federated Share request was successful, you will receive a invitation. Check your notifications.')]);
+		}
+
+		// if we doesn't get the expected response we assume that we try to add
+		// a federated share from a Nextcloud <= 9 server
+		return $this->legacyMountPublicLink($token, $remote, $password, $name, $owner, $ownerDisplayName);
+	}
+
+	/**
+	 * Allow Nextcloud to mount a public link directly
+	 *
+	 * This code was copied from the apps/files_sharing/ajax/external.php with
+	 * minimal changes, just to guarantee backward compatibility
+	 *
+	 * ToDo: Remove this method once Nextcloud 9 reaches end of life
+	 *
+	 * @param string $token
+	 * @param string $remote
+	 * @param string $password
+	 * @param string $name
+	 * @param string $owner
+	 * @param string $ownerDisplayName
+	 * @return JSONResponse
+	 */
+	private function legacyMountPublicLink($token, $remote, $password, $name, $owner, $ownerDisplayName) {
+
+		// Check for invalid name
+		if (!\OCP\Util::isValidFileName($name)) {
+			return new JSONResponse(['message' => $this->l->t('The mountpoint name contains invalid characters.')], Http::STATUS_BAD_REQUEST);
+		}
+		$currentUser = $this->userSession->getUser()->getUID();
+		$currentServer = $this->addressHandler->generateRemoteURL();
+		if (\OC\Share\Helper::isSameUserOnSameServer($owner, $remote, $currentUser, $currentServer)) {
+			return new JSONResponse(['message' => $this->l->t('Not allowed to create a federated share with the owner.')], Http::STATUS_BAD_REQUEST);
+		}
+		$discoveryManager = new \OCA\FederatedFileSharing\DiscoveryManager(
+			\OC::$server->getMemCacheFactory(),
+			\OC::$server->getHTTPClientService()
+		);
+		$externalManager = new \OCA\Files_Sharing\External\Manager(
+			\OC::$server->getDatabaseConnection(),
+			\OC\Files\Filesystem::getMountManager(),
+			\OC\Files\Filesystem::getLoader(),
+			\OC::$server->getHTTPHelper(),
+			\OC::$server->getNotificationManager(),
+			$discoveryManager,
+			\OC::$server->getUserSession()->getUser()->getUID()
+		);
+
+		// check for ssl cert
+		if (substr($remote, 0, 5) === 'https') {
+			try {
+				$client = $this->clientService->newClient();
+				$client->get($remote, [
+					'timeout' => 10,
+					'connect_timeout' => 10,
+				])->getBody();
+			} catch (\Exception $e) {
+				return new JSONResponse(['message' => $this->l->t('Invalid or untrusted SSL certificate')], Http::STATUS_BAD_REQUEST);
+			}
+		}
+		$mount = $externalManager->addShare($remote, $token, $password, $name, $ownerDisplayName, true);
+		/**
+		 * @var \OCA\Files_Sharing\External\Storage $storage
+		 */
+		$storage = $mount->getStorage();
+		try {
+			// check if storage exists
+			$storage->checkStorageAvailability();
+		} catch (\OCP\Files\StorageInvalidException $e) {
+			// note: checkStorageAvailability will already remove the invalid share
+			\OCP\Util::writeLog(
+				'federatedfilesharing',
+				'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
+				\OCP\Util::DEBUG
+			);
+			return new JSONResponse(['message' => $this->l->t('Could not authenticate to remote share, password might be wrong')], Http::STATUS_BAD_REQUEST);
+		} catch (\Exception $e) {
+			\OCP\Util::writeLog(
+				'federatedfilesharing',
+				'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
+				\OCP\Util::DEBUG
+			);
+			$externalManager->removeShare($mount->getMountPoint());
+			return new JSONResponse(['message' => $this->l->t('Storage not valid')], Http::STATUS_BAD_REQUEST);
+		}
+		$result = $storage->file_exists('');
+		if ($result) {
+			try {
+				$storage->getScanner()->scanAll();
+				return new JSONResponse(
+					[
+						'message' => $this->l->t('Federated Share successfully added'),
+						'legacyMount' => '1'
+					]
+				);
+			} catch (\OCP\Files\StorageInvalidException $e) {
+				\OCP\Util::writeLog(
+					'federatedfilesharing',
+					'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
+					\OCP\Util::DEBUG
+				);
+				return new JSONResponse(['message' => $this->l->t('Storage not valid')], Http::STATUS_BAD_REQUEST);
+			} catch (\Exception $e) {
+				\OCP\Util::writeLog(
+					'federatedfilesharing',
+					'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
+					\OCP\Util::DEBUG
+				);
+				return new JSONResponse(['message' => $this->l->t('Couldn\'t add remote share')], Http::STATUS_BAD_REQUEST);
+			}
+		} else {
+			$externalManager->removeShare($mount->getMountPoint());
+			\OCP\Util::writeLog(
+				'federatedfilesharing',
+				'Couldn\'t add remote share',
+				\OCP\Util::DEBUG
+			);
+			return new JSONResponse(['message' => $this->l->t('Couldn\'t add remote share')], Http::STATUS_BAD_REQUEST);
+		}
+
+	}
+
+}
diff --git a/apps/federatedfilesharing/lib/FederatedShareProvider.php b/apps/federatedfilesharing/lib/FederatedShareProvider.php
index 1ea31f2dbc038f839333cdb5cdb66770e7e2919e..7b64b56a16d7fcf8954d3b92ffe8c1c4166f4958 100644
--- a/apps/federatedfilesharing/lib/FederatedShareProvider.php
+++ b/apps/federatedfilesharing/lib/FederatedShareProvider.php
@@ -135,7 +135,7 @@ class FederatedShareProvider implements IShareProvider {
 		$itemType = $share->getNodeType();
 		$permissions = $share->getPermissions();
 		$sharedBy = $share->getSharedBy();
-		
+
 		/*
 		 * Check if file is not already shared with the remote user
 		 */
@@ -626,7 +626,7 @@ class FederatedShareProvider implements IShareProvider {
 			->from('share')
 			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
 			->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_REMOTE)));
-		
+
 		$cursor = $qb->execute();
 		$data = $cursor->fetch();
 		$cursor->closeCursor();
@@ -727,13 +727,13 @@ class FederatedShareProvider implements IShareProvider {
 		$data = $cursor->fetch();
 
 		if ($data === false) {
-			throw new ShareNotFound();
+			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
 		}
 
 		try {
 			$share = $this->createShareObject($data);
 		} catch (InvalidShare $e) {
-			throw new ShareNotFound();
+			throw new ShareNotFound('Share not found', $this->l->t('Could not find share'));
 		}
 
 		return $share;
diff --git a/apps/federatedfilesharing/settings-admin.php b/apps/federatedfilesharing/settings-admin.php
index 9875dcf3b5b8d27bc0a226ebfb8165d6f2bc7adf..dc5a4d6826cf5ade9961b82ab850031466b816df 100644
--- a/apps/federatedfilesharing/settings-admin.php
+++ b/apps/federatedfilesharing/settings-admin.php
@@ -22,7 +22,7 @@
 
 use OCA\FederatedFileSharing\AppInfo\Application;
 
-$app = new Application('federatedfilesharing');
+$app = new Application();
 $federatedShareProvider = $app->getFederatedShareProvider();
 
 $tmpl = new OCP\Template('federatedfilesharing', 'settings-admin');
diff --git a/apps/federatedfilesharing/settings-personal.php b/apps/federatedfilesharing/settings-personal.php
index a36cdd712c45fb22ae5bbc21dbeebff844628e97..261d540f48d1885b268edeca6e9cbfa9e4d68b65 100644
--- a/apps/federatedfilesharing/settings-personal.php
+++ b/apps/federatedfilesharing/settings-personal.php
@@ -27,7 +27,7 @@ use OCA\FederatedFileSharing\AppInfo\Application;
 
 $l = \OC::$server->getL10N('federatedfilesharing');
 
-$app = new Application('federatedfilesharing');
+$app = new Application();
 $federatedShareProvider = $app->getFederatedShareProvider();
 
 $isIE8 = false;
diff --git a/apps/federatedfilesharing/tests/Controller/MountPublicLinkControllerTest.php b/apps/federatedfilesharing/tests/Controller/MountPublicLinkControllerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3fe05e72cf4abe5440e6abb319f5a678eb912ca3
--- /dev/null
+++ b/apps/federatedfilesharing/tests/Controller/MountPublicLinkControllerTest.php
@@ -0,0 +1,200 @@
+<?php
+/**
+ * @author Björn Schießle <schiessle@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, Björn Schießle <bjoern@schiessle.org>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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, version 3,
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+namespace OCA\FederatedFileSharing\Tests\Controller;
+
+use OC\HintException;
+use OCA\FederatedFileSharing\AddressHandler;
+use OCA\FederatedFileSharing\Controller\MountPublicLinkController;
+use OCA\FederatedFileSharing\FederatedShareProvider;
+use OCP\AppFramework\Http;
+use OCP\Files\IRootFolder;
+use OCP\Http\Client\IClientService;
+use OCP\IL10N;
+use OCP\ISession;
+use OCP\IUserManager;
+use OCP\IUserSession;
+use OCP\Share\IManager;
+use OCP\Share\IShare;
+
+class MountPublicLinkControllerTest extends \Test\TestCase {
+
+	/** @var  MountPublicLinkController */
+	private $controller;
+
+	/** @var  \OCP\IRequest | \PHPUnit_Framework_MockObject_MockObject */
+	private $request;
+
+	/** @var  FederatedShareProvider | \PHPUnit_Framework_MockObject_MockObject */
+	private $federatedShareProvider;
+
+	/** @var  IManager | \PHPUnit_Framework_MockObject_MockObject */
+	private $shareManager;
+
+	/** @var  AddressHandler | \PHPUnit_Framework_MockObject_MockObject */
+	private $addressHandler;
+
+	/** @var  IRootFolder | \PHPUnit_Framework_MockObject_MockObject */
+	private $rootFolder;
+
+	/** @var  IUserManager | \PHPUnit_Framework_MockObject_MockObject */
+	private $userManager;
+
+	/** @var  ISession | \PHPUnit_Framework_MockObject_MockObject */
+	private $session;
+
+	/** @var  IL10N | \PHPUnit_Framework_MockObject_MockObject */
+	private $l10n;
+
+	/** @var  IUserSession | \PHPUnit_Framework_MockObject_MockObject */
+	private $userSession;
+
+	/** @var  IClientService | \PHPUnit_Framework_MockObject_MockObject */
+	private $clientService;
+
+	/** @var  IShare */
+	private $share;
+
+	public function setUp() {
+		parent::setUp();
+
+		$this->request = $this->getMockBuilder('OCP\IRequest')->disableOriginalConstructor()->getMock();
+		$this->federatedShareProvider = $this->getMockBuilder('OCA\FederatedFileSharing\FederatedShareProvider')
+			->disableOriginalConstructor()->getMock();
+		$this->shareManager = $this->getMockBuilder('OCP\Share\IManager')->disableOriginalConstructor()->getMock();
+		$this->addressHandler = $this->getMockBuilder('OCA\FederatedFileSharing\AddressHandler')
+			->disableOriginalConstructor()->getMock();
+		$this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')->disableOriginalConstructor()->getMock();
+		$this->userManager = $this->getMockBuilder('OCP\IUserManager')->disableOriginalConstructor()->getMock();
+		$this->share = new \OC\Share20\Share($this->rootFolder, $this->userManager);
+		$this->session = $this->getMockBuilder('OCP\ISession')->disableOriginalConstructor()->getMock();
+		$this->l10n = $this->getMockBuilder('OCP\IL10N')->disableOriginalConstructor()->getMock();
+		$this->userSession = $this->getMockBuilder('OCP\IUserSession')->disableOriginalConstructor()->getMock();
+		$this->clientService = $this->getMockBuilder('OCP\Http\Client\IClientService')->disableOriginalConstructor()->getMock();
+
+		$this->controller = new MountPublicLinkController(
+			'federatedfilesharing', $this->request,
+			$this->federatedShareProvider,
+			$this->shareManager,
+			$this->addressHandler,
+			$this->session,
+			$this->l10n,
+			$this->userSession,
+			$this->clientService
+		);
+	}
+
+	/**
+	 * @dataProvider dataTestCreateFederatedShare
+	 *
+	 * @param string $shareWith
+	 * @param bool $outgoingSharesAllowed
+	 * @param bool $validShareWith
+	 * @param string $token
+	 * @param bool $validToken
+	 * @param bool $createSuccessful
+	 * @param string $expectedReturnData
+	 */
+	public function testCreateFederatedShare($shareWith,
+											 $outgoingSharesAllowed,
+											 $validShareWith,
+											 $token,
+											 $validToken,
+											 $createSuccessful,
+											 $expectedReturnData
+	) {
+
+		$this->federatedShareProvider->expects($this->any())
+			->method('isOutgoingServer2serverShareEnabled')
+			->willReturn($outgoingSharesAllowed);
+
+		$this->addressHandler->expects($this->any())->method('splitUserRemote')
+			->with($shareWith)
+			->willReturnCallback(
+				function($shareWith) use ($validShareWith, $expectedReturnData) {
+					if ($validShareWith) {
+						return ['user', 'server'];
+					}
+					throw new HintException($expectedReturnData, $expectedReturnData);
+				}
+			);
+
+		$share = $this->share;
+
+		$this->shareManager->expects($this->any())->method('getShareByToken')
+			->with($token)
+			->willReturnCallback(
+				function ($token) use ($validToken, $share, $expectedReturnData) {
+					if ($validToken) {
+						return $share;
+					}
+					throw new HintException($expectedReturnData, $expectedReturnData);
+				}
+			);
+
+		$this->federatedShareProvider->expects($this->any())->method('create')
+			->with($share)
+			->willReturnCallback(
+				function (IShare $share) use ($createSuccessful, $shareWith, $expectedReturnData) {
+					$this->assertEquals($shareWith, $share->getSharedWith());
+					if ($createSuccessful) {
+						return $share;
+					}
+					throw new HintException($expectedReturnData, $expectedReturnData);
+				}
+			);
+
+		$result = $this->controller->createFederatedShare($shareWith, $token);
+
+		$errorCase = !$validShareWith || !$validToken || !$createSuccessful || !$outgoingSharesAllowed;
+
+		if ($errorCase) {
+			$this->assertSame(Http::STATUS_BAD_REQUEST, $result->getStatus());
+			$this->assertTrue(isset($result->getData()['message']));
+			$this->assertSame($expectedReturnData, $result->getData()['message']);
+		} else {
+			$this->assertSame(Http::STATUS_OK, $result->getStatus());
+			$this->assertTrue(isset($result->getData()['remoteUrl']));
+			$this->assertSame($expectedReturnData, $result->getData()['remoteUrl']);
+
+		}
+
+	}
+
+	public function dataTestCreateFederatedShare() {
+		return [
+			//shareWith, outgoingSharesAllowed, validShareWith, token, validToken, createSuccessful, expectedReturnData
+			['user@server', true, true, 'token', true, true, 'server'],
+			['user@server', true, false, 'token', true, true, 'invalid federated cloud id'],
+			['user@server', true, false, 'token', false, true, 'invalid federated cloud id'],
+			['user@server', true, false, 'token', false, false, 'invalid federated cloud id'],
+			['user@server', true, false, 'token', true, false, 'invalid federated cloud id'],
+			['user@server', true, true, 'token', false, true, 'invalid token'],
+			['user@server', true, true, 'token', false, false, 'invalid token'],
+			['user@server', true, true, 'token', true, false, 'can not create share'],
+			['user@server', false, true, 'token', true, true, 'This server doesn\'t support outgoing federated shares'],
+		];
+	}
+
+}
diff --git a/apps/files_sharing/tests/js/externalSpec.js b/apps/federatedfilesharing/tests/js/externalSpec.js
similarity index 100%
rename from apps/files_sharing/tests/js/externalSpec.js
rename to apps/federatedfilesharing/tests/js/externalSpec.js
diff --git a/apps/files_sharing/ajax/external.php b/apps/files_sharing/ajax/external.php
deleted file mode 100644
index 4a7a6096c911f802cc062bfcc967e7e8125c7e28..0000000000000000000000000000000000000000
--- a/apps/files_sharing/ajax/external.php
+++ /dev/null
@@ -1,153 +0,0 @@
-<?php
-/**
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Joas Schilling <nickvergessen@owncloud.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <icewind@owncloud.com>
- * @author Roeland Jago Douma <rullzer@owncloud.com>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- * @license AGPL-3.0
- *
- * This code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * 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, version 3,
- * along with this program.  If not, see <http://www.gnu.org/licenses/>
- *
- */
-
-OCP\JSON::callCheck();
-OCP\JSON::checkLoggedIn();
-OCP\JSON::checkAppEnabled('files_sharing');
-
-$l = \OC::$server->getL10N('files_sharing');
-
-$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application('federatedfilesharing');
-$federatedShareProvider = $federatedSharingApp->getFederatedShareProvider();
-
-// check if server admin allows to mount public links from other servers
-if ($federatedShareProvider->isIncomingServer2serverShareEnabled() === false) {
-	\OCP\JSON::error(array('data' => array('message' => $l->t('Server to server sharing is not enabled on this server'))));
-	exit();
-}
-
-$token = $_POST['token'];
-$remote = $_POST['remote'];
-$owner = $_POST['owner'];
-$ownerDisplayName = $_POST['ownerDisplayName'];
-$name = $_POST['name'];
-$password = $_POST['password'];
-
-// Check for invalid name
-if(!\OCP\Util::isValidFileName($name)) {
-	\OCP\JSON::error(array('data' => array('message' => $l->t('The mountpoint name contains invalid characters.'))));
-	exit();
-}
-
-$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
-$currentServer = \OC::$server->getURLGenerator()->getAbsoluteURL('/');
-if (\OC\Share\Helper::isSameUserOnSameServer($owner, $remote, $currentUser, $currentServer )) {
-	\OCP\JSON::error(array('data' => array('message' => $l->t('Not allowed to create a federated share with the same user server'))));
-	exit();
-}
-
-$discoveryManager = new \OCA\FederatedFileSharing\DiscoveryManager(
-	\OC::$server->getMemCacheFactory(),
-	\OC::$server->getHTTPClientService()
-);
-$externalManager = new \OCA\Files_Sharing\External\Manager(
-		\OC::$server->getDatabaseConnection(),
-		\OC\Files\Filesystem::getMountManager(),
-		\OC\Files\Filesystem::getLoader(),
-		\OC::$server->getHTTPHelper(),
-		\OC::$server->getNotificationManager(),
-		$discoveryManager,
-		\OC::$server->getUserSession()->getUser()->getUID()
-);
-
-// check for ssl cert
-if (substr($remote, 0, 5) === 'https') {
-	try {
-		\OC::$server->getHTTPClientService()->newClient()->get($remote, [
-			'timeout' => 10,
-			'connect_timeout' => 10,
-		])->getBody();
-	} catch (\Exception $e) {
-		\OCP\JSON::error(array('data' => array('message' => $l->t('Invalid or untrusted SSL certificate'))));
-		exit;
-	}
-}
-
-$mount = $externalManager->addShare($remote, $token, $password, $name, $ownerDisplayName, true);
-
-/**
- * @var \OCA\Files_Sharing\External\Storage $storage
- */
-$storage = $mount->getStorage();
-try {
-	// check if storage exists
-	$storage->checkStorageAvailability();
-} catch (\OCP\Files\StorageInvalidException $e) {
-	// note: checkStorageAvailability will already remove the invalid share
-	\OCP\Util::writeLog(
-		'files_sharing',
-		'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
-		\OCP\Util::DEBUG
-	);
-	\OCP\JSON::error(
-		array(
-			'data' => array(
-				'message' => $l->t('Could not authenticate to remote share, password might be wrong')
-			)
-		)
-	);
-	exit();
-} catch (\Exception $e) {
-	\OCP\Util::writeLog(
-		'files_sharing',
-		'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
-		\OCP\Util::DEBUG
-	);
-	$externalManager->removeShare($mount->getMountPoint());
-	\OCP\JSON::error(array('data' => array('message' => $l->t('Storage not valid'))));
-	exit();
-}
-$result = $storage->file_exists('');
-if ($result) {
-	try {
-		$storage->getScanner()->scanAll();
-		\OCP\JSON::success();
-	} catch (\OCP\Files\StorageInvalidException $e) {
-		\OCP\Util::writeLog(
-			'files_sharing',
-			'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
-			\OCP\Util::DEBUG
-		);
-		\OCP\JSON::error(array('data' => array('message' => $l->t('Storage not valid'))));
-	} catch (\Exception $e) {
-		\OCP\Util::writeLog(
-			'files_sharing',
-			'Invalid remote storage: ' . get_class($e) . ': ' . $e->getMessage(),
-			\OCP\Util::DEBUG
-		);
-		\OCP\JSON::error(array('data' => array('message' => $l->t('Couldn\'t add remote share'))));
-	}
-} else {
-	$externalManager->removeShare($mount->getMountPoint());
-	\OCP\Util::writeLog(
-		'files_sharing',
-		'Couldn\'t add remote share',
-		\OCP\Util::DEBUG
-	);
-	\OCP\JSON::error(array('data' => array('message' => $l->t('Couldn\'t add remote share'))));
-}
-
diff --git a/apps/files_sharing/ajax/shareinfo.php b/apps/files_sharing/ajax/shareinfo.php
index 0b93e3d2ee943e97577f8747636bfd949edb4389..31b8e00f496edac2d4ed3bd2a47141b91dcc2f43 100644
--- a/apps/files_sharing/ajax/shareinfo.php
+++ b/apps/files_sharing/ajax/shareinfo.php
@@ -31,7 +31,7 @@ if (!isset($_GET['t'])) {
 	exit;
 }
 
-$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application('federatedfilesharing');
+$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application();
 $federatedShareProvider = $federatedSharingApp->getFederatedShareProvider();
 
 if ($federatedShareProvider->isOutgoingServer2serverShareEnabled() === false) {
diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php
index c6ae6903eec2c75e506f96b13d310e24bf619ecb..219fa298d51fae72f3f505bbfb3e30a0470509cb 100644
--- a/apps/files_sharing/appinfo/app.php
+++ b/apps/files_sharing/appinfo/app.php
@@ -46,9 +46,6 @@ $eventDispatcher->addListener(
 	function() {
 		\OCP\Util::addScript('files_sharing', 'share');
 		\OCP\Util::addScript('files_sharing', 'sharetabview');
-		if (\OC::$server->getConfig()->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'yes') {
-			\OCP\Util::addScript('files_sharing', 'external');
-		}
 		\OCP\Util::addStyle('files_sharing', 'sharetabview');
 	}
 );
diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php
index 0e72934d094b273763f24aeddcab722cbcd365c3..26d32c3a990f553af5a95891077a97cbc893ea20 100644
--- a/apps/files_sharing/appinfo/routes.php
+++ b/apps/files_sharing/appinfo/routes.php
@@ -53,8 +53,6 @@ $this->create('files_sharing_ajax_publicpreview', 'ajax/publicpreview.php')
 	->actionInclude('files_sharing/ajax/publicpreview.php');
 $this->create('sharing_external_shareinfo', '/shareinfo')
 	->actionInclude('files_sharing/ajax/shareinfo.php');
-$this->create('sharing_external_add', '/external')
-	->actionInclude('files_sharing/ajax/external.php');
 
 // OCS API
 
diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js
index 3befeaeda1f3fe3b97c4ee905b1e757c016be80d..0dfff235998da5c4db01097ce1da59ee35eaf7b7 100644
--- a/apps/files_sharing/js/public.js
+++ b/apps/files_sharing/js/public.js
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2014
+ * @copyright Copyright (c) 2016, Björn Schießle <bjoern@schiessle.org>
  *
  * This file is licensed under the Affero General Public License version 3
  * or later.
@@ -247,7 +248,7 @@ OCA.Sharing.PublicApp = {
 			var ownerDisplayName = $('#save').data('owner-display-name');
 			var name = $('#save').data('name');
 			var isProtected = $('#save').data('protected') ? 1 : 0;
-			OCA.Sharing.PublicApp._saveToOwnCloud(remote, token, owner, ownerDisplayName, name, isProtected);
+			OCA.Sharing.PublicApp._createFederatedShare(remote, token, owner, ownerDisplayName, name, isProtected);
 		});
 
 		$('#remote_address').on("keyup paste", function() {
@@ -294,30 +295,26 @@ OCA.Sharing.PublicApp = {
 		this.fileList.changeDirectory(params.path || params.dir, false, true);
 	},
 
-	_saveToOwnCloud: function (remote, token, owner, ownerDisplayName, name, isProtected) {
-		var toggleLoading = function() {
-			var iconClass = $('#save-button-confirm').attr('class');
-			var loading = iconClass.indexOf('icon-loading-small') !== -1;
-			if(loading) {
-				$('#save-button-confirm')
-				.removeClass("icon-loading-small")
-				.addClass("icon-confirm");
 
-			}
-			else {
-				$('#save-button-confirm')
-				.removeClass("icon-confirm")
-				.addClass("icon-loading-small");
-
-			}
-		};
+	/**
+	 * fall back to old behaviour where we redirect the user to his server to mount
+	 * the public link instead of creating a dedicated federated share
+	 *
+	 * @param remote
+	 * @param token
+	 * @param owner
+	 * @param ownerDisplayName
+	 * @param name
+	 * @param isProtected
+	 * @private
+	 */
+	_legacyCreateFederatedShare: function (remote, token, owner, ownerDisplayName, name, isProtected) {
 
-		toggleLoading();
 		var location = window.location.protocol + '//' + window.location.host + OC.webroot;
 
 		if(remote.substr(-1) !== '/') {
 			remote += '/'
-		};
+		}
 
 		var url = remote + 'index.php/apps/files#' + 'remote=' + encodeURIComponent(location) // our location is the remote for the other server
 			+ "&token=" + encodeURIComponent(token) + "&owner=" + encodeURIComponent(owner) +"&ownerDisplayName=" + encodeURIComponent(ownerDisplayName) + "&name=" + encodeURIComponent(name) + "&protected=" + isProtected;
@@ -330,7 +327,6 @@ OCA.Sharing.PublicApp = {
 			// this check needs to happen on the server due to the Content Security Policy directive
 			$.get(OC.generateUrl('apps/files_sharing/testremote'), {remote: remote}).then(function (protocol) {
 				if (protocol !== 'http' && protocol !== 'https') {
-					toggleLoading();
 					OC.dialogs.alert(t('files_sharing', 'No compatible server found at {remote}', {remote: remote}),
 						t('files_sharing', 'Invalid server URL'));
 				} else {
@@ -338,6 +334,58 @@ OCA.Sharing.PublicApp = {
 				}
 			});
 		}
+	},
+
+	_createFederatedShare: function (remote, token, owner, ownerDisplayName, name, isProtected) {
+
+		var toggleLoading = function() {
+			var iconClass = $('#save-button-confirm').attr('class');
+			var loading = iconClass.indexOf('icon-loading-small') !== -1;
+			if(loading) {
+				$('#save-button-confirm')
+					.removeClass("icon-loading-small")
+					.addClass("icon-confirm");
+
+			}
+			else {
+				$('#save-button-confirm')
+					.removeClass("icon-confirm")
+					.addClass("icon-loading-small");
+
+			}
+		};
+
+		toggleLoading();
+
+		if (remote.indexOf('@') === -1) {
+			this._legacyCreateFederatedShare(remote, token, owner, ownerDisplayName, name, isProtected);
+			toggleLoading();
+			return;
+		}
+
+		$.post(
+			OC.generateUrl('/apps/federatedfilesharing/createFederatedShare'),
+			{
+				'shareWith': remote,
+				'token': token
+			}
+		).done(
+			function (data) {
+				var url = data.remoteUrl;
+
+				if (url.indexOf('://') > 0) {
+					OC.redirect(url);
+				} else {
+					OC.redirect('http://' + url);
+				}
+			}
+		).fail(
+			function (jqXHR) {
+				OC.dialogs.alert(JSON.parse(jqXHR.responseText).message,
+					t('files_sharing', 'Failed to add the public link to your Nextcloud'));
+				toggleLoading();
+			}
+		);
 	}
 };
 
diff --git a/apps/files_sharing/lib/AppInfo/Application.php b/apps/files_sharing/lib/AppInfo/Application.php
index fda16c7acac8c543cbf9367bbe4675e89462e2c0..5ed8d886e2ee54a06e242ae29aaddb6f69cfc00b 100644
--- a/apps/files_sharing/lib/AppInfo/Application.php
+++ b/apps/files_sharing/lib/AppInfo/Application.php
@@ -46,7 +46,7 @@ class Application extends App {
 		 * Controllers
 		 */
 		$container->registerService('ShareController', function (SimpleContainer $c) use ($server) {
-			$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application('federatedfilesharing');
+			$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application();
 			return new ShareController(
 				$c->query('AppName'),
 				$c->query('Request'),
diff --git a/apps/files_sharing/lib/share/file.php b/apps/files_sharing/lib/share/file.php
index 4643e46eeb2976397d801bb42c8a3457d71be568..e7588a589e83e162d7f8f89b70727f86fadde6cf 100644
--- a/apps/files_sharing/lib/share/file.php
+++ b/apps/files_sharing/lib/share/file.php
@@ -77,7 +77,7 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
 		if ($federatedShareProvider) {
 			$this->federatedShareProvider = $federatedShareProvider;
 		} else {
-			$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application('federatedfilesharing');
+			$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application();
 			$this->federatedShareProvider = $federatedSharingApp->getFederatedShareProvider();
 		}
 	}
diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php
index c15001ad24bcb9924716a284abb5bb9e43e00de1..8a906f02a7e0747420c0f9fe96320ff3bc02dfa6 100644
--- a/apps/files_sharing/templates/public.php
+++ b/apps/files_sharing/templates/public.php
@@ -82,9 +82,9 @@ $maxUploadFilesize = min($upload_max_filesize, $post_max_size);
 						?>
 						<span id="save" data-protected="<?php p($_['protected']) ?>"
 							  data-owner-display-name="<?php p($_['displayName']) ?>" data-owner="<?php p($_['owner']) ?>" data-name="<?php p($_['filename']) ?>">
-						<button id="save-button"><?php p($l->t('Add to your ownCloud')) ?></button>
+						<button id="save-button"><?php p($l->t('Add to your Nextcloud')) ?></button>
 						<form class="save-form hidden" action="#">
-							<input type="text" id="remote_address" placeholder="example.com/owncloud"/>
+							<input type="text" id="remote_address" placeholder="user@yourNextcloud.org"/>
 							<button id="save-button-confirm" class="icon-confirm svg" disabled></button>
 						</form>
 					</span>
diff --git a/ocs/routes.php b/ocs/routes.php
index d9c78a4a16a0afda3cc791b63005b6123adeb5ab..c465e08e877bd85e0a13b57472b6b66a14f0107f 100644
--- a/ocs/routes.php
+++ b/ocs/routes.php
@@ -99,7 +99,7 @@ API::register(
 
 // Server-to-Server Sharing
 if (\OC::$server->getAppManager()->isEnabledForUser('files_sharing')) {
-	$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application('federatedfilesharing');
+	$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application();
 	$addressHandler = new \OCA\FederatedFileSharing\AddressHandler(
 		\OC::$server->getURLGenerator(),
 		\OC::$server->getL10N('federatedfilesharing')