diff --git a/apps/files_external/appinfo/app.php b/apps/files_external/appinfo/app.php
index ca164784fb011724a4c3578a5367b8b1b11724ab..e88880fe516b994c1700ce779de61607c300bb4a 100644
--- a/apps/files_external/appinfo/app.php
+++ b/apps/files_external/appinfo/app.php
@@ -20,12 +20,23 @@ OC::$CLASSPATH['OC\Files\Storage\AmazonS3'] = 'files_external/lib/amazons3.php';
 OC::$CLASSPATH['OC\Files\Storage\Dropbox'] = 'files_external/lib/dropbox.php';
 OC::$CLASSPATH['OC\Files\Storage\SFTP'] = 'files_external/lib/sftp.php';
 OC::$CLASSPATH['OC_Mount_Config'] = 'files_external/lib/config.php';
+OC::$CLASSPATH['OCA\Files\External\Api'] = 'files_external/lib/api.php';
 
 OCP\App::registerAdmin('files_external', 'settings');
 if (OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes') == 'yes') {
 	OCP\App::registerPersonal('files_external', 'personal');
 }
 
+\OCA\Files\App::getNavigationManager()->add(
+	array(
+		"id" => 'extstoragemounts',
+		"appname" => 'files_external',
+		"script" => 'list.php',
+		"order" => 30,
+		"name" => $l->t('External storage')
+	)
+);
+
 // connecting hooks
 OCP\Util::connectHook('OC_Filesystem', 'post_initMountPoints', '\OC_Mount_Config', 'initMountPointsHook');
 OCP\Util::connectHook('OC_User', 'post_login', 'OC\Files\Storage\SMB_OC', 'login');
@@ -164,3 +175,4 @@ OC_Mount_Config::registerBackend('\OC\Files\Storage\SFTP', array(
 		'user' => (string)$l->t('Username'),
 		'password' => '*'.$l->t('Password'),
 		'root' => '&'.$l->t('Root'))));
+
diff --git a/apps/files_external/appinfo/routes.php b/apps/files_external/appinfo/routes.php
new file mode 100644
index 0000000000000000000000000000000000000000..cb950364e5de23c2d08527b7b98ffbc0e3e7320a
--- /dev/null
+++ b/apps/files_external/appinfo/routes.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * ownCloud - External Storage Routes
+ *
+ * @author Vincent Petry
+ * @copyright 2014 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library 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 library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+OC_API::register('get',
+		'/apps/files_external/api/v1/mounts',
+		array('\OCA\Files\External\Api', 'getUserMounts'),
+		'files_external');
+
diff --git a/apps/files_external/js/app.js b/apps/files_external/js/app.js
new file mode 100644
index 0000000000000000000000000000000000000000..58ad1a0f6ef96a06e1a4760fe8950baa3b9abe4d
--- /dev/null
+++ b/apps/files_external/js/app.js
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+if (!OCA.External) {
+	OCA.External = {};
+}
+OCA.External.App = {
+
+	fileList: null,
+
+	initList: function($el) {
+		if (this.fileList) {
+			return this.fileList;
+		}
+
+		this.fileList = new OCA.External.FileList(
+			$el,
+			{
+				scrollContainer: $('#app-content'),
+				fileActions: this._createFileActions()
+			}
+		);
+
+		this._extendFileList(this.fileList);
+		this.fileList.appName = t('files_external', 'External storage');
+		return this.fileList;
+	},
+
+	removeList: function() {
+		if (this.fileList) {
+			this.fileList.$fileList.empty();
+		}
+	},
+
+	_createFileActions: function() {
+		// inherit file actions from the files app
+		var fileActions = new OCA.Files.FileActions();
+		fileActions.registerDefaultActions();
+
+		// when the user clicks on a folder, redirect to the corresponding
+		// folder in the files app instead of opening it directly
+		fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
+			OCA.Files.App.setActiveView('files', {silent: true});
+			OCA.Files.App.fileList.changeDirectory(context.$file.attr('data-path') + '/' + filename, true, true);
+		});
+		fileActions.setDefault('dir', 'Open');
+		return fileActions;
+	},
+
+	_extendFileList: function(fileList) {
+		// remove size column from summary
+		fileList.fileSummary.$el.find('.filesize').remove();
+	}
+};
+
+$(document).ready(function() {
+	$('#app-content-extstoragemounts').on('show', function(e) {
+		OCA.External.App.initList($(e.target));
+	});
+	$('#app-content-extstoragemounts').on('hide', function() {
+		OCA.External.App.removeList();
+	});
+});
+
diff --git a/apps/files_external/js/mountsfilelist.js b/apps/files_external/js/mountsfilelist.js
new file mode 100644
index 0000000000000000000000000000000000000000..52a9aff728c9e1b8ac2cb5da93309c6ead4342ee
--- /dev/null
+++ b/apps/files_external/js/mountsfilelist.js
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+(function() {
+
+	/**
+	 * External storage file list
+	 */
+	var FileList = function($el, options) {
+		this.initialize($el, options);
+	};
+
+	FileList.prototype = _.extend({}, OCA.Files.FileList.prototype, {
+		appName: 'External storage',
+
+		initialize: function($el, options) {
+			OCA.Files.FileList.prototype.initialize.apply(this, arguments);
+			if (this.initialized) {
+				return;
+			}
+		},
+
+		_createRow: function(fileData) {
+			// TODO: hook earlier and render the whole row here
+			var $tr = OCA.Files.FileList.prototype._createRow.apply(this, arguments);
+			$tr.find('.filesize,.date').remove();
+			$tr.find('td.filename').after('<td></td>');
+			$tr.find('td.filename input:checkbox').remove();
+			return $tr;
+		},
+
+		updateEmptyContent: function() {
+			var dir = this.getCurrentDirectory();
+			if (dir === '/') {
+				// root has special permissions
+				this.$el.find('#emptycontent').toggleClass('hidden', !this.isEmpty);
+				this.$el.find('#filestable thead th').toggleClass('hidden', this.isEmpty);
+			}
+			else {
+				OCA.Files.FileList.prototype.updateEmptyContent.apply(this, arguments);
+			}
+		},
+
+		getDirectoryPermissions: function() {
+			return OC.PERMISSION_READ | OC.PERMISSION_DELETE;
+		},
+
+		updateStorageStatistics: function() {
+			// no op because it doesn't have
+			// storage info like free space / used space
+		},
+
+		reload: function() {
+			var self = this;
+			this.showMask();
+			if (this._reloadCall) {
+				this._reloadCall.abort();
+			}
+			this._reloadCall = $.ajax({
+				url: OC.linkToOCS('apps/files_external/api/v1') + 'mounts',
+				data: {
+					format: 'json'
+				},
+				type: 'GET',
+				beforeSend: function(xhr) {
+					xhr.setRequestHeader('OCS-APIREQUEST', 'true');
+				},
+				error: function(result) {
+					self.reloadCallback(result);
+				},
+				success: function(result) {
+					self.reloadCallback(result);
+				}
+			});
+		},
+
+		reloadCallback: function(result) {
+			delete this._reloadCall;
+			this.hideMask();
+
+			if (result.ocs && result.ocs.data) {
+				this.setFiles(this._makeFiles(result.ocs.data));
+			}
+			else {
+				// TODO: error handling
+			}
+		},
+
+		/**
+		 * Converts the OCS API  response data to a file info
+		 * list
+		 * @param OCS API mounts array
+		 * @return array of file info maps
+		 */
+		_makeFiles: function(data) {
+			var files = _.chain(data)
+				.map(function(fileData) {
+					fileData.icon = OC.imagePath('core', 'filetypes/folder-external');
+					return fileData;
+				})
+				// Sort by expected sort comparator
+				.sortBy(this._sortComparator)
+				.value();
+
+			return files;
+		}
+	});
+
+	OCA.External.FileList = FileList;
+})();
diff --git a/apps/files_external/lib/api.php b/apps/files_external/lib/api.php
new file mode 100644
index 0000000000000000000000000000000000000000..d94dbcffc8f5be605afdda870360d65f33b3e95a
--- /dev/null
+++ b/apps/files_external/lib/api.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Vincent Petry
+ * @copyright 2014 Vincent Petry pvince81@owncloud.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library 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 library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files\External;
+
+class Api {
+
+	/**
+	 * Returns the mount points visible for this user.
+	 *
+	 * @param array $params
+	 * @return \OC_OCS_Result share information
+	 */
+	public static function getUserMounts($params) {
+		$entries = array();
+		$user = \OC_User::getUser();
+		$mounts = \OC_Mount_Config::getAbsoluteMountPoints($user);
+
+		foreach ($mounts as $mountPoint => $config) {
+			// split user name from mount point
+			$parts = explode('/', ltrim($mountPoint, '/'));
+			array_shift($parts); // use name
+			array_shift($parts); // files
+			$mountPoint = implode('/', $parts);
+
+			$path = dirname($mountPoint);
+			if ($path === '.') {
+				$path = '';
+			}
+
+			// TODO: give delete permissions if mount type is personal
+			$permissions = \OCP\PERMISSION_READ;
+
+			// TODO: add storageType, might need to use another OC_Mount_Config method
+			$entries[] = array(
+				'name' => basename($mountPoint),
+				'path' => $path,
+				'type' => 'dir',
+				'permissions' => $permissions
+			);
+		}
+
+		return new \OC_OCS_Result($entries);
+	}
+}
diff --git a/apps/files_external/list.php b/apps/files_external/list.php
new file mode 100644
index 0000000000000000000000000000000000000000..e9517724f2f2dc79ceb3a5f49e6213780fa304b8
--- /dev/null
+++ b/apps/files_external/list.php
@@ -0,0 +1,11 @@
+<?php
+
+// Check if we are a user
+OCP\User::checkLoggedIn();
+
+$tmpl = new OCP\Template('files_external', 'list', '');
+
+OCP\Util::addScript('files_external', 'app');
+OCP\Util::addScript('files_external', 'mountsfilelist');
+
+$tmpl->printPage();
diff --git a/apps/files_external/templates/list.php b/apps/files_external/templates/list.php
new file mode 100644
index 0000000000000000000000000000000000000000..225616e8cf2464ccc835c9c2ac5ec49bce6e7b91
--- /dev/null
+++ b/apps/files_external/templates/list.php
@@ -0,0 +1,25 @@
+<?php /** @var $l OC_L10N */ ?>
+<div id="controls">
+	<div id="file_action_panel"></div>
+</div>
+<div id='notification'></div>
+
+<div id="emptycontent" class="hidden"><?php p($l->t( 'You don\'t have any external storages' )); ?></div>
+
+<input type="hidden" name="dir" value="" id="dir">
+
+<table id="filestable">
+	<thead>
+		<tr>
+			<th id='headerName' class="hidden column-name">
+				<div id="headerName-container">
+					<a class="name sort columntitle" data-sort="name"><span><?php p($l->t( 'Name' )); ?></span><span class="sort-indicator"></span></a>
+				</div>
+			</th>
+		</tr>
+	</thead>
+	<tbody id="fileList">
+	</tbody>
+	<tfoot>
+	</tfoot>
+</table>