diff --git a/core/Controller/LoginController.php b/core/Controller/LoginController.php
index 884eea8869ef39ba8977b7d5e4c82f4b1039aa85..71478470ffe3ec3c12ba85635e693c4a68f526c5 100644
--- a/core/Controller/LoginController.php
+++ b/core/Controller/LoginController.php
@@ -196,9 +196,10 @@ class LoginController extends Controller {
 	 * @param string $user
 	 * @param string $password
 	 * @param string $redirect_url
+	 * @param boolean $remember_login
 	 * @return RedirectResponse
 	 */
-	public function tryLogin($user, $password, $redirect_url) {
+	public function tryLogin($user, $password, $redirect_url, $remember_login = false) {
 		$currentDelay = $this->throttler->getDelay($this->request->getRemoteAddress());
 		$this->throttler->sleepDelay($this->request->getRemoteAddress());
 
@@ -236,13 +237,13 @@ class LoginController extends Controller {
 		// TODO: remove password checks from above and let the user session handle failures
 		// requires https://github.com/owncloud/core/pull/24616
 		$this->userSession->login($user, $password);
-		$this->userSession->createSessionToken($this->request, $loginResult->getUID(), $user, $password);
+		$this->userSession->createSessionToken($this->request, $loginResult->getUID(), $user, $password, $remember_login);
 
 		// User has successfully logged in, now remove the password reset link, when it is available
 		$this->config->deleteUserValue($loginResult->getUID(), 'core', 'lostpassword');
 
 		if ($this->twoFactorManager->isTwoFactorAuthenticated($loginResult)) {
-			$this->twoFactorManager->prepareTwoFactorLogin($loginResult);
+			$this->twoFactorManager->prepareTwoFactorLogin($loginResult, $remember_login);
 
 			$providers = $this->twoFactorManager->getProviders($loginResult);
 			if (count($providers) === 1) {
@@ -265,6 +266,10 @@ class LoginController extends Controller {
 			return new RedirectResponse($this->urlGenerator->linkToRoute($url, $urlParams));
 		}
 
+		if ($remember_login) {
+			$this->userSession->createRememberMeToken($loginResult);
+		}
+
 		return $this->generateRedirect($redirect_url);
 	}
 
diff --git a/db_structure.xml b/db_structure.xml
index 77f6d7689863f4286a6bd822574a9fa4f0d07394..09dbde710d30fb507b78c74cb791249bd38932e9 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -1125,6 +1125,15 @@
 				<length>2</length>
 			</field>
 
+			<field>
+				<name>remember</name>
+				<type>integer</type>
+				<default>0</default>
+				<notnull>true</notnull>
+				<unsigned>true</unsigned>
+				<length>1</length>
+			</field>
+
 			<field>
 				<name>last_activity</name>
 				<type>integer</type>
diff --git a/lib/base.php b/lib/base.php
index e7bedb6959631c87cced39ba8ca7ddd91519a3c0..28fc57161c3a627ae578e294a319f14bb6629478 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -1035,6 +1035,12 @@ class OC {
 		if ($userSession->tryTokenLogin($request)) {
 			return true;
 		}
+		if (isset($_COOKIE['nc_username'])
+			&& isset($_COOKIE['nc_token'])
+			&& isset($_COOKIE['nc_session_id'])
+			&& $userSession->loginWithCookie($_COOKIE['nc_username'], $_COOKIE['nc_token'], $_COOKIE['nc_session_id'])) {
+			return true;
+		}
 		if ($userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
 			return true;
 		}
diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php
index a1e845f132ecbd2b86e41397ae294e3e5e5d1b1e..e1516c47ed6bc2c23b17d4a9d6e80367a1d68e4a 100644
--- a/lib/private/AppFramework/DependencyInjection/DIContainer.php
+++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php
@@ -290,6 +290,7 @@ class DIContainer extends SimpleContainer implements IAppContainer {
 		$this->registerService('OCP\\IUserSession', function($c) {
 			return $this->getServer()->getUserSession();
 		});
+		$this->registerAlias(\OC\User\Session::class, \OCP\IUserSession::class);
 
 		$this->registerService('OCP\\ISession', function($c) {
 			return $this->getServer()->getSession();
diff --git a/lib/private/Authentication/Token/DefaultToken.php b/lib/private/Authentication/Token/DefaultToken.php
index 904df9baa28da05cd4fcbcb10973373a4fce1cc1..faef2f73b33dfd84c93c04fe3dc6a63ab0b6879e 100644
--- a/lib/private/Authentication/Token/DefaultToken.php
+++ b/lib/private/Authentication/Token/DefaultToken.php
@@ -35,6 +35,8 @@ use OCP\AppFramework\Db\Entity;
  * @method string getToken()
  * @method void setType(string $type)
  * @method int getType()
+ * @method void setRemember(int $remember)
+ * @method int getRemember()
  * @method void setLastActivity(int $lastActivity)
  * @method int getLastActivity()
  */
@@ -70,6 +72,11 @@ class DefaultToken extends Entity implements IToken {
 	 */
 	protected $type;
 
+	/**
+	 * @var int
+	 */
+	protected $remember;
+
 	/**
 	 * @var int
 	 */
diff --git a/lib/private/Authentication/Token/DefaultTokenMapper.php b/lib/private/Authentication/Token/DefaultTokenMapper.php
index 0ce26197ccfe59c23160b967a7445b313d8ecafc..752974ff24033af274418ff0f314dfd4b2227fba 100644
--- a/lib/private/Authentication/Token/DefaultTokenMapper.php
+++ b/lib/private/Authentication/Token/DefaultTokenMapper.php
@@ -40,24 +40,25 @@ class DefaultTokenMapper extends Mapper {
 	 * @param string $token
 	 */
 	public function invalidate($token) {
+		/* @var $qb IQueryBuilder */
 		$qb = $this->db->getQueryBuilder();
 		$qb->delete('authtoken')
-			->andWhere($qb->expr()->eq('token', $qb->createParameter('token')))
+			->where($qb->expr()->eq('token', $qb->createParameter('token')))
 			->setParameter('token', $token)
 			->execute();
 	}
 
 	/**
 	 * @param int $olderThan
+	 * @param int $remember
 	 */
-	public function invalidateOld($olderThan) {
+	public function invalidateOld($olderThan, $remember = IToken::DO_NOT_REMEMBER) {
 		/* @var $qb IQueryBuilder */
 		$qb = $this->db->getQueryBuilder();
 		$qb->delete('authtoken')
-			->where($qb->expr()->lt('last_activity', $qb->createParameter('last_activity')))
-			->andWhere($qb->expr()->eq('type', $qb->createParameter('type')))
-			->setParameter('last_activity', $olderThan, IQueryBuilder::PARAM_INT)
-			->setParameter('type', IToken::TEMPORARY_TOKEN, IQueryBuilder::PARAM_INT)
+			->where($qb->expr()->lt('last_activity', $qb->createNamedParameter($olderThan, IQueryBuilder::PARAM_INT)))
+			->andWhere($qb->expr()->eq('type', $qb->createNamedParameter(IToken::TEMPORARY_TOKEN, IQueryBuilder::PARAM_INT)))
+			->andWhere($qb->expr()->eq('remember', $qb->createNamedParameter($remember, IQueryBuilder::PARAM_INT)))
 			->execute();
 	}
 
@@ -71,7 +72,7 @@ class DefaultTokenMapper extends Mapper {
 	public function getToken($token) {
 		/* @var $qb IQueryBuilder */
 		$qb = $this->db->getQueryBuilder();
-		$result = $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'token', 'last_activity', 'last_check')
+		$result = $qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'remember', 'token', 'last_activity', 'last_check')
 			->from('authtoken')
 			->where($qb->expr()->eq('token', $qb->createParameter('token')))
 			->setParameter('token', $token)
@@ -97,7 +98,7 @@ class DefaultTokenMapper extends Mapper {
 	public function getTokenByUser(IUser $user) {
 		/* @var $qb IQueryBuilder */
 		$qb = $this->db->getQueryBuilder();
-		$qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'token', 'last_activity', 'last_check')
+		$qb->select('id', 'uid', 'login_name', 'password', 'name', 'type', 'remember', 'token', 'last_activity', 'last_check')
 			->from('authtoken')
 			->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())))
 			->setMaxResults(1000);
diff --git a/lib/private/Authentication/Token/DefaultTokenProvider.php b/lib/private/Authentication/Token/DefaultTokenProvider.php
index b0fbeb9b47ec6c13ab774ebda154aa8bb8956023..87f434c684c56bd12b9ce02055a8bd933b0d40cc 100644
--- a/lib/private/Authentication/Token/DefaultTokenProvider.php
+++ b/lib/private/Authentication/Token/DefaultTokenProvider.php
@@ -1,6 +1,7 @@
 <?php
 /**
  * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, Christoph Wurst <christoph@winzerhof-wurst.at>
  *
  * @author Christoph Wurst <christoph@owncloud.com>
  *
@@ -56,7 +57,11 @@ class DefaultTokenProvider implements IProvider {
 	 * @param ILogger $logger
 	 * @param ITimeFactory $time
 	 */
-	public function __construct(DefaultTokenMapper $mapper, ICrypto $crypto, IConfig $config, ILogger $logger, ITimeFactory $time) {
+	public function __construct(DefaultTokenMapper $mapper,
+								ICrypto $crypto,
+								IConfig $config,
+								ILogger $logger,
+								ITimeFactory $time) {
 		$this->mapper = $mapper;
 		$this->crypto = $crypto;
 		$this->config = $config;
@@ -73,9 +78,10 @@ class DefaultTokenProvider implements IProvider {
 	 * @param string|null $password
 	 * @param string $name
 	 * @param int $type token type
+	 * @param int $remember whether the session token should be used for remember-me
 	 * @return IToken
 	 */
-	public function generateToken($token, $uid, $loginName, $password, $name, $type = IToken::TEMPORARY_TOKEN) {
+	public function generateToken($token, $uid, $loginName, $password, $name, $type = IToken::TEMPORARY_TOKEN, $remember = IToken::DO_NOT_REMEMBER) {
 		$dbToken = new DefaultToken();
 		$dbToken->setUid($uid);
 		$dbToken->setLoginName($loginName);
@@ -85,6 +91,7 @@ class DefaultTokenProvider implements IProvider {
 		$dbToken->setName($name);
 		$dbToken->setToken($this->hashToken($token));
 		$dbToken->setType($type);
+		$dbToken->setRemember($remember);
 		$dbToken->setLastActivity($this->time->getTime());
 
 		$this->mapper->insert($dbToken);
@@ -96,6 +103,7 @@ class DefaultTokenProvider implements IProvider {
 	 * Save the updated token
 	 *
 	 * @param IToken $token
+	 * @throws InvalidTokenException
 	 */
 	public function updateToken(IToken $token) {
 		if (!($token instanceof DefaultToken)) {
@@ -151,6 +159,28 @@ class DefaultTokenProvider implements IProvider {
 		}
 	}
 
+	/**
+	 * @param string $oldSessionId
+	 * @param string $sessionId
+	 * @throws InvalidTokenException
+	 */
+	public function renewSessionToken($oldSessionId, $sessionId) {
+		$token = $this->getToken($oldSessionId);
+
+		$newToken = new DefaultToken();
+		$newToken->setUid($token->getUID());
+		$newToken->setLoginName($token->getLoginName());
+		if (!is_null($token->getPassword())) {
+			$password = $this->decryptPassword($token->getPassword(), $oldSessionId);
+			$newToken->setPassword($this->encryptPassword($password, $sessionId));
+		}
+		$newToken->setName($token->getName());
+		$newToken->setToken($this->hashToken($sessionId));
+		$newToken->setType(IToken::TEMPORARY_TOKEN);
+		$newToken->setLastActivity($this->time->getTime());
+		$this->mapper->insert($newToken);
+	}
+
 	/**
 	 * @param IToken $savedToken
 	 * @param string $tokenId session token
@@ -207,8 +237,11 @@ class DefaultTokenProvider implements IProvider {
 	 */
 	public function invalidateOldTokens() {
 		$olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
-		$this->logger->info('Invalidating tokens older than ' . date('c', $olderThan));
-		$this->mapper->invalidateOld($olderThan);
+		$this->logger->info('Invalidating session tokens older than ' . date('c', $olderThan));
+		$this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
+		$rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
+		$this->logger->info('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold));
+		$this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
 	}
 
 	/**
diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php
index 65b515960ea4ed443f69de6ec356f7088ed0f216..ce14a5880c55f0d2220aa56fdd94d307c4f6f7d9 100644
--- a/lib/private/Authentication/Token/IProvider.php
+++ b/lib/private/Authentication/Token/IProvider.php
@@ -28,6 +28,7 @@ use OCP\IUser;
 
 interface IProvider {
 
+
 	/**
 	 * Create and persist a new token
 	 *
@@ -37,9 +38,10 @@ interface IProvider {
 	 * @param string|null $password
 	 * @param string $name
 	 * @param int $type token type
+	 * @param int $remember whether the session token should be used for remember-me
 	 * @return IToken
 	 */
-	public function generateToken($token, $uid, $loginName, $password, $name, $type = IToken::TEMPORARY_TOKEN);
+	public function generateToken($token, $uid, $loginName, $password, $name, $type = IToken::TEMPORARY_TOKEN, $remember = IToken::DO_NOT_REMEMBER);
 
 	/**
 	 * Get a token by token id
@@ -50,6 +52,15 @@ interface IProvider {
 	 */
 	public function getToken($tokenId) ;
 
+	/**
+	 * Duplicate an existing session token
+	 *
+	 * @param string $oldSessionId
+	 * @param string $sessionId
+	 * @throws InvalidTokenException
+	 */
+	public function renewSessionToken($oldSessionId, $sessionId);
+
 	/**
 	 * Invalidate (delete) the given session token
 	 *
diff --git a/lib/private/Authentication/Token/IToken.php b/lib/private/Authentication/Token/IToken.php
index e1e78ca369a4961d3be44c2a0a8c4835ce4ec62d..14811dd3201a07e22ae5cadb58fe18ac6cbba6b6 100644
--- a/lib/private/Authentication/Token/IToken.php
+++ b/lib/private/Authentication/Token/IToken.php
@@ -28,6 +28,8 @@ interface IToken extends JsonSerializable {
 
 	const TEMPORARY_TOKEN = 0;
 	const PERMANENT_TOKEN = 1;
+	const DO_NOT_REMEMBER = 0;
+	const REMEMBER = 1;
 
 	/**
 	 * Get the token ID
diff --git a/lib/private/Authentication/TwoFactorAuth/Manager.php b/lib/private/Authentication/TwoFactorAuth/Manager.php
index 1bea7aa3478d0f1c582a0567dc05dff50e377ed6..d84ba4aee7ecfb3662c1a6f01d661a0239709387 100644
--- a/lib/private/Authentication/TwoFactorAuth/Manager.php
+++ b/lib/private/Authentication/TwoFactorAuth/Manager.php
@@ -37,6 +37,7 @@ class Manager {
 	const SESSION_UID_KEY = 'two_factor_auth_uid';
 	const BACKUP_CODES_APP_ID = 'twofactor_backupcodes';
 	const BACKUP_CODES_PROVIDER_ID = 'backup_codes';
+	const REMEMBER_LOGIN = 'two_factor_remember_login';
 
 	/** @var AppManager */
 	private $appManager;
@@ -114,6 +115,7 @@ class Manager {
 	 * @param IUser $user
 	 * @param bool $includeBackupApp
 	 * @return IProvider[]
+	 * @throws Exception
 	 */
 	public function getProviders(IUser $user, $includeBackupApp = false) {
 		$allApps = $this->appManager->getEnabledAppsForUser($user);
@@ -171,11 +173,16 @@ class Manager {
 			return false;
 		}
 
-		$result = $provider->verifyChallenge($user, $challenge);
-		if ($result) {
+		$passed = $provider->verifyChallenge($user, $challenge);
+		if ($passed) {
+			if ($this->session->get(self::REMEMBER_LOGIN) === true) {
+				// TODO: resolve cyclic dependency and use DI
+				\OC::$server->getUserSession()->createRememberMeToken($user);
+			}
 			$this->session->remove(self::SESSION_UID_KEY);
+			$this->session->remove(self::REMEMBER_LOGIN);
 		}
-		return $result;
+		return $passed;
 	}
 
 	/**
@@ -202,12 +209,14 @@ class Manager {
 	}
 
 	/**
-	 * Prepare the 2FA login (set session value)
+	 * Prepare the 2FA login
 	 *
 	 * @param IUser $user
+	 * @param boolean $rememberMe
 	 */
-	public function prepareTwoFactorLogin(IUser $user) {
+	public function prepareTwoFactorLogin(IUser $user, $rememberMe) {
 		$this->session->set(self::SESSION_UID_KEY, $user->getUID());
+		$this->session->set(self::REMEMBER_LOGIN, $rememberMe);
 	}
 
 }
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 3ea358498da16351afa2bbfb8603b0a3195b687e..6f25098eb357f0b4dee8ceab11d528cb5b4a6bb3 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -245,7 +245,7 @@ class Server extends ServerContainer implements IServerContainer {
 				$defaultTokenProvider = null;
 			}
 
-			$userSession = new \OC\User\Session($manager, $session, $timeFactory, $defaultTokenProvider, $c->getConfig());
+			$userSession = new \OC\User\Session($manager, $session, $timeFactory, $defaultTokenProvider, $c->getConfig(), $c->getSecureRandom());
 			$userSession->listen('\OC\User', 'preCreateUser', function ($uid, $password) {
 				\OC_Hook::emit('OC_User', 'pre_createUser', array('run' => true, 'uid' => $uid, 'password' => $password));
 			});
@@ -286,7 +286,7 @@ class Server extends ServerContainer implements IServerContainer {
 			return $userSession;
 		});
 
-		$this->registerService('\OC\Authentication\TwoFactorAuth\Manager', function (Server $c) {
+		$this->registerService(\OC\Authentication\TwoFactorAuth\Manager::class, function (Server $c) {
 			return new \OC\Authentication\TwoFactorAuth\Manager($c->getAppManager(), $c->getSession(), $c->getConfig());
 		});
 
diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php
index a213ee48c2ab62de689c9dd23bb751942272447a..7215cbe418886a64b36b1dad004b01c95eb8fa8e 100644
--- a/lib/private/User/Session.php
+++ b/lib/private/User/Session.php
@@ -48,6 +48,7 @@ use OCP\ISession;
 use OCP\IUser;
 use OCP\IUserManager;
 use OCP\IUserSession;
+use OCP\Security\ISecureRandom;
 use OCP\Session\Exceptions\SessionNotAvailableException;
 use OCP\Util;
 
@@ -89,23 +90,29 @@ class Session implements IUserSession, Emitter {
 	/** @var User $activeUser */
 	protected $activeUser;
 
+	/** @var ISecureRandom */
+	private $random;
+
 	/**
 	 * @param IUserManager $manager
 	 * @param ISession $session
 	 * @param ITimeFactory $timeFacory
 	 * @param IProvider $tokenProvider
 	 * @param IConfig $config
+	 * @param ISecureRandom $random
 	 */
 	public function __construct(IUserManager $manager,
 								ISession $session,
 								ITimeFactory $timeFacory,
 								$tokenProvider,
-								IConfig $config) {
+								IConfig $config,
+								ISecureRandom $random) {
 		$this->manager = $manager;
 		$this->session = $session;
 		$this->timeFacory = $timeFacory;
 		$this->tokenProvider = $tokenProvider;
 		$this->config = $config;
+		$this->random = $random;
 	}
 
 	/**
@@ -526,9 +533,10 @@ class Session implements IUserSession, Emitter {
 	 * @param string $uid user UID
 	 * @param string $loginName login name
 	 * @param string $password
+	 * @param int $remember
 	 * @return boolean
 	 */
-	public function createSessionToken(IRequest $request, $uid, $loginName, $password = null) {
+	public function createSessionToken(IRequest $request, $uid, $loginName, $password = null, $remember = IToken::DO_NOT_REMEMBER) {
 		if (is_null($this->manager->get($uid))) {
 			// User does not exist
 			return false;
@@ -537,7 +545,7 @@ class Session implements IUserSession, Emitter {
 		try {
 			$sessionId = $this->session->getId();
 			$pwd = $this->getPassword($password);
-			$this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name);
+			$this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name, IToken::TEMPORARY_TOKEN, IToken::REMEMBER);
 			return true;
 		} catch (SessionNotAvailableException $ex) {
 			// This can happen with OCC, where a memory session is used
@@ -680,9 +688,10 @@ class Session implements IUserSession, Emitter {
 	 *
 	 * @param string $uid the username
 	 * @param string $currentToken
+	 * @param string $oldSessionId
 	 * @return bool
 	 */
-	public function loginWithCookie($uid, $currentToken) {
+	public function loginWithCookie($uid, $currentToken, $oldSessionId) {
 		$this->session->regenerateId();
 		$this->manager->emit('\OC\User', 'preRememberedLogin', array($uid));
 		$user = $this->manager->get($uid);
@@ -692,15 +701,26 @@ class Session implements IUserSession, Emitter {
 		}
 
 		// get stored tokens
-		$tokens = OC::$server->getConfig()->getUserKeys($uid, 'login_token');
+		$tokens = $this->config->getUserKeys($uid, 'login_token');
 		// test cookies token against stored tokens
 		if (!in_array($currentToken, $tokens, true)) {
 			return false;
 		}
 		// replace successfully used token with a new one
-		OC::$server->getConfig()->deleteUserValue($uid, 'login_token', $currentToken);
-		$newToken = OC::$server->getSecureRandom()->generate(32);
-		OC::$server->getConfig()->setUserValue($uid, 'login_token', $newToken, time());
+		$this->config->deleteUserValue($uid, 'login_token', $currentToken);
+		$newToken = $this->random->generate(32);
+		$this->config->setUserValue($uid, 'login_token', $newToken, $this->timeFacory->getTime());
+
+		try {
+			$sessionId = $this->session->getId();
+			$this->tokenProvider->renewSessionToken($oldSessionId, $sessionId);
+		} catch (SessionNotAvailableException $ex) {
+			return false;
+		} catch (InvalidTokenException $ex) {
+			\OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']);
+			return false;
+		}
+
 		$this->setMagicInCookie($user->getUID(), $newToken);
 
 		//login
@@ -709,6 +729,15 @@ class Session implements IUserSession, Emitter {
 		return true;
 	}
 
+	/**
+	 * @param IUser $user
+	 */
+	public function createRememberMeToken(IUser $user) {
+		$token = $this->random->generate(32);
+		$this->config->setUserValue($user->getUID(), 'login_token', $token, $this->timeFacory->getTime());
+		$this->setMagicInCookie($user->getUID(), $token);
+	}
+
 	/**
 	 * logout the user from the session
 	 */
@@ -736,10 +765,19 @@ class Session implements IUserSession, Emitter {
 	 */
 	public function setMagicInCookie($username, $token) {
 		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
-		$expires = time() + OC::$server->getConfig()->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
-		setcookie('oc_username', $username, $expires, OC::$WEBROOT, '', $secureCookie, true);
-		setcookie('oc_token', $token, $expires, OC::$WEBROOT, '', $secureCookie, true);
-		setcookie('oc_remember_login', '1', $expires, OC::$WEBROOT, '', $secureCookie, true);
+		$webRoot = \OC::$WEBROOT;
+		if ($webRoot === '') {
+			$webRoot = '/';
+		}
+
+		$expires = $this->timeFacory->getTime() + $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
+		setcookie('nc_username', $username, $expires, $webRoot, '', $secureCookie, true);
+		setcookie('nc_token', $token, $expires, $webRoot, '', $secureCookie, true);
+		try {
+			setcookie('nc_session_id', $this->session->getId(), $expires, $webRoot, '', $secureCookie, true);
+		} catch (SessionNotAvailableException $ex) {
+			// ignore
+		}
 	}
 
 	/**
@@ -749,17 +787,17 @@ class Session implements IUserSession, Emitter {
 		//TODO: DI for cookies and IRequest
 		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
 
-		unset($_COOKIE['oc_username']); //TODO: DI
-		unset($_COOKIE['oc_token']);
-		unset($_COOKIE['oc_remember_login']);
-		setcookie('oc_username', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
-		setcookie('oc_token', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
-		setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT, '', $secureCookie, true);
+		unset($_COOKIE['nc_username']); //TODO: DI
+		unset($_COOKIE['nc_token']);
+		unset($_COOKIE['nc_session_id']);
+		setcookie('nc_username', '', $this->timeFacory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
+		setcookie('nc_token', '', $this->timeFacory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
+		setcookie('nc_session_id', '', $this->timeFacory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
 		// old cookies might be stored under /webroot/ instead of /webroot
 		// and Firefox doesn't like it!
-		setcookie('oc_username', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
-		setcookie('oc_token', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
-		setcookie('oc_remember_login', '', time() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
+		setcookie('nc_username', '', $this->timeFacory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
+		setcookie('nc_token', '', $this->timeFacory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
+		setcookie('nc_session_id', '', $this->timeFacory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
 	}
 
 	/**
@@ -779,4 +817,5 @@ class Session implements IUserSession, Emitter {
 		}
 	}
 
+
 }
diff --git a/lib/private/legacy/user.php b/lib/private/legacy/user.php
index af2382dbb8648b5826e281869ce4d9b03babe699..ed0d14a1ab91b39928c2a073b7a361044c25fc6a 100644
--- a/lib/private/legacy/user.php
+++ b/lib/private/legacy/user.php
@@ -155,10 +155,11 @@ class OC_User {
 	 * @deprecated use \OCP\IUserSession::loginWithCookie()
 	 * @param string $uid The username of the user to log in
 	 * @param string $token
+	 * @param string $oldSessionId
 	 * @return bool
 	 */
-	public static function loginWithCookie($uid, $token) {
-		return self::getUserSession()->loginWithCookie($uid, $token);
+	public static function loginWithCookie($uid, $token, $oldSessionId) {
+		return self::getUserSession()->loginWithCookie($uid, $token, $oldSessionId);
 	}
 
 	/**
diff --git a/lib/public/IRequest.php b/lib/public/IRequest.php
index 11242c481f0ef7d298a46cdee313b893753379fd..b36a934b0c21be3ee3ca2b8f446daca152431f86 100644
--- a/lib/public/IRequest.php
+++ b/lib/public/IRequest.php
@@ -145,7 +145,7 @@ interface IRequest {
 	 * Shortcut for getting cookie variables
 	 *
 	 * @param string $key the key that will be taken from the $_COOKIE array
-	 * @return string the value in the $_COOKIE element
+	 * @return string|null the value in the $_COOKIE element
 	 * @since 6.0.0
 	 */
 	public function getCookie($key);
diff --git a/tests/Core/Controller/LoginControllerTest.php b/tests/Core/Controller/LoginControllerTest.php
index ff50ac98fbd751969146a523edac5a7f3d6c8222..d16b9b114f35c4047fc1f9ea311f55b854bd5a8b 100644
--- a/tests/Core/Controller/LoginControllerTest.php
+++ b/tests/Core/Controller/LoginControllerTest.php
@@ -322,6 +322,8 @@ class LoginControllerTest extends TestCase {
 
 		$this->userSession->expects($this->never())
 			->method('createSessionToken');
+		$this->userSession->expects($this->never())
+			->method('createRememberMeToken');
 		$this->config->expects($this->never())
 			->method('deleteUserValue');
 
@@ -363,7 +365,7 @@ class LoginControllerTest extends TestCase {
 			->with($user, $password);
 		$this->userSession->expects($this->once())
 			->method('createSessionToken')
-			->with($this->request, $user->getUID(), $user, $password);
+			->with($this->request, $user->getUID(), $user, $password, false);
 		$this->twoFactorManager->expects($this->once())
 			->method('isTwoFactorAuthenticated')
 			->with($user)
@@ -371,11 +373,63 @@ class LoginControllerTest extends TestCase {
 		$this->config->expects($this->once())
 			->method('deleteUserValue')
 			->with('uid', 'core', 'lostpassword');
+		$this->userSession->expects($this->never())
+			->method('createRememberMeToken');
 
 		$expected = new \OCP\AppFramework\Http\RedirectResponse($indexPageUrl);
 		$this->assertEquals($expected, $this->loginController->tryLogin($user, $password, null));
 	}
 
+	public function testLoginWithValidCredentialsAndRememberMe() {
+		/** @var IUser | \PHPUnit_Framework_MockObject_MockObject $user */
+		$user = $this->getMockBuilder('\OCP\IUser')->getMock();
+		$user->expects($this->any())
+			->method('getUID')
+			->will($this->returnValue('uid'));
+		$password = 'secret';
+		$indexPageUrl = \OC_Util::getDefaultPageUrl();
+
+		$this->request
+			->expects($this->exactly(2))
+			->method('getRemoteAddress')
+			->willReturn('192.168.0.1');
+		$this->request
+			->expects($this->once())
+			->method('passesCSRFCheck')
+			->willReturn(true);
+		$this->throttler
+			->expects($this->once())
+			->method('sleepDelay')
+			->with('192.168.0.1');
+		$this->throttler
+			->expects($this->once())
+			->method('getDelay')
+			->with('192.168.0.1')
+			->willReturn(200);
+		$this->userManager->expects($this->once())
+			->method('checkPassword')
+			->will($this->returnValue($user));
+		$this->userSession->expects($this->once())
+			->method('login')
+			->with($user, $password);
+		$this->userSession->expects($this->once())
+			->method('createSessionToken')
+			->with($this->request, $user->getUID(), $user, $password, true);
+		$this->twoFactorManager->expects($this->once())
+			->method('isTwoFactorAuthenticated')
+			->with($user)
+			->will($this->returnValue(false));
+		$this->config->expects($this->once())
+			->method('deleteUserValue')
+			->with('uid', 'core', 'lostpassword');
+		$this->userSession->expects($this->once())
+			->method('createRememberMeToken')
+			->with($user);
+
+		$expected = new \OCP\AppFramework\Http\RedirectResponse($indexPageUrl);
+		$this->assertEquals($expected, $this->loginController->tryLogin($user, $password, null, true));
+	}
+
 	public function testLoginWithoutPassedCsrfCheckAndNotLoggedIn() {
 		/** @var IUser | \PHPUnit_Framework_MockObject_MockObject $user */
 		$user = $this->getMockBuilder('\OCP\IUser')->getMock();
@@ -408,6 +462,8 @@ class LoginControllerTest extends TestCase {
 			->will($this->returnValue(false));
 		$this->config->expects($this->never())
 			->method('deleteUserValue');
+		$this->userSession->expects($this->never())
+			->method('createRememberMeToken');
 
 		$expected = new \OCP\AppFramework\Http\RedirectResponse(\OC_Util::getDefaultPageUrl());
 		$this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl));
@@ -450,6 +506,8 @@ class LoginControllerTest extends TestCase {
 			->will($this->returnValue($redirectUrl));
 		$this->config->expects($this->never())
 			->method('deleteUserValue');
+		$this->userSession->expects($this->never())
+			->method('createRememberMeToken');
 
 		$expected = new \OCP\AppFramework\Http\RedirectResponse($redirectUrl);
 		$this->assertEquals($expected, $this->loginController->tryLogin('Jane', $password, $originalUrl));
@@ -488,7 +546,7 @@ class LoginControllerTest extends TestCase {
 			->will($this->returnValue($user));
 		$this->userSession->expects($this->once())
 			->method('createSessionToken')
-			->with($this->request, $user->getUID(), 'Jane', $password);
+			->with($this->request, $user->getUID(), 'Jane', $password, false);
 		$this->userSession->expects($this->once())
 			->method('isLoggedIn')
 			->with()
@@ -540,7 +598,7 @@ class LoginControllerTest extends TestCase {
 			->with('john@doe.com', $password);
 		$this->userSession->expects($this->once())
 			->method('createSessionToken')
-			->with($this->request, $user->getUID(), 'john@doe.com', $password);
+			->with($this->request, $user->getUID(), 'john@doe.com', $password, false);
 		$this->twoFactorManager->expects($this->once())
 			->method('isTwoFactorAuthenticated')
 			->with($user)
@@ -564,6 +622,8 @@ class LoginControllerTest extends TestCase {
 		$this->config->expects($this->once())
 			->method('deleteUserValue')
 			->with('john', 'core', 'lostpassword');
+		$this->userSession->expects($this->never())
+			->method('createRememberMeToken');
 
 		$expected = new RedirectResponse($challengeUrl);
 		$this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', $password, null));
@@ -605,7 +665,7 @@ class LoginControllerTest extends TestCase {
 			->with('john@doe.com', $password);
 		$this->userSession->expects($this->once())
 			->method('createSessionToken')
-			->with($this->request, $user->getUID(), 'john@doe.com', $password);
+			->with($this->request, $user->getUID(), 'john@doe.com', $password, false);
 		$this->twoFactorManager->expects($this->once())
 			->method('isTwoFactorAuthenticated')
 			->with($user)
@@ -628,6 +688,8 @@ class LoginControllerTest extends TestCase {
 		$this->config->expects($this->once())
 			->method('deleteUserValue')
 			->with('john', 'core', 'lostpassword');
+		$this->userSession->expects($this->never())
+			->method('createRememberMeToken');
 
 		$expected = new RedirectResponse($challengeUrl);
 		$this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', $password, null));
@@ -680,6 +742,8 @@ class LoginControllerTest extends TestCase {
 			->with('login', '192.168.0.1', ['user' => 'john@doe.com']);
 		$this->config->expects($this->never())
 			->method('deleteUserValue');
+		$this->userSession->expects($this->never())
+			->method('createRememberMeToken');
 
 		$expected = new RedirectResponse('');
 		$this->assertEquals($expected, $this->loginController->tryLogin('john@doe.com', 'just wrong', null));
diff --git a/tests/lib/Authentication/Token/DefaultTokenMapperTest.php b/tests/lib/Authentication/Token/DefaultTokenMapperTest.php
index d71d94684774cf4bc3df48180c4628db9678ea42..418a4d14f624f21ffafd7b460b7a0c327d5400b2 100644
--- a/tests/lib/Authentication/Token/DefaultTokenMapperTest.php
+++ b/tests/lib/Authentication/Token/DefaultTokenMapperTest.php
@@ -130,6 +130,7 @@ class DefaultTokenMapperTest extends TestCase {
 		$token->setName('Firefox on Android');
 		$token->setToken('1504445f1524fc801035448a95681a9378ba2e83930c814546c56e5d6ebde221198792fd900c88ed5ead0555780dad1ebce3370d7e154941cd5de87eb419899b');
 		$token->setType(IToken::TEMPORARY_TOKEN);
+		$token->setRemember(IToken::DO_NOT_REMEMBER);
 		$token->setLastActivity($this->time - 60 * 60 * 24 * 3);
 		$token->setLastCheck($this->time - 10);
 
diff --git a/tests/lib/Authentication/Token/DefaultTokenProviderTest.php b/tests/lib/Authentication/Token/DefaultTokenProviderTest.php
index 7f90cf051f48f658334c98340c54484c7edca2a8..5e4d4f9436664b8db8037151d03a48dc2c8ffb3b 100644
--- a/tests/lib/Authentication/Token/DefaultTokenProviderTest.php
+++ b/tests/lib/Authentication/Token/DefaultTokenProviderTest.php
@@ -1,8 +1,8 @@
 <?php
-
 /**
  * @author Christoph Wurst <christoph@owncloud.com>
  *
+ * @copyright Copyright (c) 2016, Lukas Reschke <lukas@statuscode.ch>
  * @copyright Copyright (c) 2016, ownCloud, Inc.
  * @license AGPL-3.0
  *
@@ -25,7 +25,7 @@ namespace Test\Authentication\Token;
 use OC\Authentication\Token\DefaultToken;
 use OC\Authentication\Token\DefaultTokenProvider;
 use OC\Authentication\Token\IToken;
-use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Db\Mapper;
 use OCP\AppFramework\Utility\ITimeFactory;
 use OCP\IConfig;
 use OCP\ILogger;
@@ -35,13 +35,19 @@ use Test\TestCase;
 
 class DefaultTokenProviderTest extends TestCase {
 
-	/** @var DefaultTokenProvider */
+	/** @var DefaultTokenProvider|\PHPUnit_Framework_MockObject_MockObject */
 	private $tokenProvider;
+	/** @var Mapper|\PHPUnit_Framework_MockObject_MockObject */
 	private $mapper;
+	/** @var ICrypto|\PHPUnit_Framework_MockObject_MockObject */
 	private $crypto;
+	/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
 	private $config;
+	/** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */
 	private $logger;
+	/** @var ITimeFactory|\PHPUnit_Framework_MockObject_MockObject */
 	private $timeFactory;
+	/** @var int */
 	private $time;
 
 	protected function setUp() {
@@ -81,6 +87,7 @@ class DefaultTokenProviderTest extends TestCase {
 		$toInsert->setName($name);
 		$toInsert->setToken(hash('sha512', $token . '1f4h9s'));
 		$toInsert->setType($type);
+		$toInsert->setRemember(IToken::DO_NOT_REMEMBER);
 		$toInsert->setLastActivity($this->time);
 
 		$this->config->expects($this->any())
@@ -95,7 +102,7 @@ class DefaultTokenProviderTest extends TestCase {
 			->method('insert')
 			->with($this->equalTo($toInsert));
 
-		$actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type);
+		$actual = $this->tokenProvider->generateToken($token, $uid, $user, $password, $name, $type, IToken::DO_NOT_REMEMBER);
 
 		$this->assertEquals($toInsert, $actual);
 	}
@@ -245,15 +252,128 @@ class DefaultTokenProviderTest extends TestCase {
 
 	public function testInvalidateOldTokens() {
 		$defaultSessionLifetime = 60 * 60 * 24;
-		$this->config->expects($this->once())
+		$defaultRememberMeLifetime = 60 * 60 * 24 * 15;
+		$this->config->expects($this->exactly(2))
 			->method('getSystemValue')
-			->with('session_lifetime', $defaultSessionLifetime)
-			->will($this->returnValue(150));
-		$this->mapper->expects($this->once())
+			->will($this->returnValueMap([
+				['session_lifetime', $defaultSessionLifetime, 150],
+				['remember_login_cookie_lifetime', $defaultRememberMeLifetime, 300],
+			]));
+		$this->mapper->expects($this->at(0))
 			->method('invalidateOld')
 			->with($this->time - 150);
+		$this->mapper->expects($this->at(1))
+			->method('invalidateOld')
+			->with($this->time - 300);
 
 		$this->tokenProvider->invalidateOldTokens();
 	}
 
+	public function testRenewSessionTokenWithoutPassword() {
+		$token = $this->getMockBuilder(DefaultToken::class)
+			->disableOriginalConstructor()
+			->setMethods(['getUID', 'getLoginName', 'getPassword', 'getName'])
+			->getMock();
+		$token
+			->expects($this->at(0))
+			->method('getUID')
+			->willReturn('UserUid');
+		$token
+			->expects($this->at(1))
+			->method('getLoginName')
+			->willReturn('UserLoginName');
+		$token
+			->expects($this->at(2))
+			->method('getPassword')
+			->willReturn(null);
+		$token
+			->expects($this->at(3))
+			->method('getName')
+			->willReturn('MyTokenName');
+		$this->config
+			->expects($this->exactly(2))
+			->method('getSystemValue')
+			->with('secret')
+			->willReturn('MyInstanceSecret');
+		$this->mapper
+			->expects($this->at(0))
+			->method('getToken')
+			->with(hash('sha512', 'oldId' . 'MyInstanceSecret'))
+			->willReturn($token);
+		$newToken = new DefaultToken();
+		$newToken->setUid('UserUid');
+		$newToken->setLoginName('UserLoginName');
+		$newToken->setName('MyTokenName');
+		$newToken->setToken(hash('sha512', 'newId' . 'MyInstanceSecret'));
+		$newToken->setType(IToken::TEMPORARY_TOKEN);
+		$newToken->setLastActivity(1313131);
+		$this->mapper
+			->expects($this->at(1))
+			->method('insert')
+			->with($newToken);
+
+		$this->tokenProvider->renewSessionToken('oldId', 'newId');
+	}
+
+	public function testRenewSessionTokenWithPassword() {
+		$token = $this->getMockBuilder(DefaultToken::class)
+			->disableOriginalConstructor()
+			->setMethods(['getUID', 'getLoginName', 'getPassword', 'getName'])
+			->getMock();
+		$token
+			->expects($this->at(0))
+			->method('getUID')
+			->willReturn('UserUid');
+		$token
+			->expects($this->at(1))
+			->method('getLoginName')
+			->willReturn('UserLoginName');
+		$token
+			->expects($this->at(2))
+			->method('getPassword')
+			->willReturn('EncryptedPassword');
+		$token
+			->expects($this->at(3))
+			->method('getPassword')
+			->willReturn('EncryptedPassword');
+		$token
+			->expects($this->at(4))
+			->method('getName')
+			->willReturn('MyTokenName');
+		$this->crypto
+			->expects($this->any(0))
+			->method('decrypt')
+			->with('EncryptedPassword', 'oldIdMyInstanceSecret')
+			->willReturn('ClearTextPassword');
+		$this->crypto
+			->expects($this->any(1))
+			->method('encrypt')
+			->with('ClearTextPassword', 'newIdMyInstanceSecret')
+			->willReturn('EncryptedPassword');
+		$this->config
+			->expects($this->exactly(4))
+			->method('getSystemValue')
+			->with('secret')
+			->willReturn('MyInstanceSecret');
+		$this->mapper
+			->expects($this->at(0))
+			->method('getToken')
+			->with(hash('sha512', 'oldId' . 'MyInstanceSecret'))
+			->willReturn($token);
+		$newToken = new DefaultToken();
+		$newToken->setUid('UserUid');
+		$newToken->setLoginName('UserLoginName');
+		$newToken->setName('MyTokenName');
+		$newToken->setToken(hash('sha512', 'newId' . 'MyInstanceSecret'));
+		$newToken->setType(IToken::TEMPORARY_TOKEN);
+		$newToken->setLastActivity(1313131);
+		$newToken->setPassword('EncryptedPassword');
+		$this->mapper
+			->expects($this->at(1))
+			->method('insert')
+			->with($newToken);
+
+		$this->tokenProvider->renewSessionToken('oldId', 'newId');
+	}
+
 }
diff --git a/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php b/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php
index 72b70d817d2c26a3bf3793d4bb16b5305d7adb5b..52f3ca285001c5be123955e4d960bd6d81206b56 100644
--- a/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php
+++ b/tests/lib/Authentication/TwoFactorAuth/ManagerTest.php
@@ -233,8 +233,15 @@ class ManagerTest extends TestCase {
 			->with($this->user, $challenge)
 			->will($this->returnValue(true));
 		$this->session->expects($this->once())
+			->method('get')
+			->with('two_factor_remember_login')
+			->will($this->returnValue(false));
+		$this->session->expects($this->at(1))
 			->method('remove')
 			->with('two_factor_auth_uid');
+		$this->session->expects($this->at(2))
+			->method('remove')
+			->with('two_factor_remember_login');
 
 		$this->assertTrue($this->manager->verifyChallenge('email', $this->user, $challenge));
 	}
@@ -304,11 +311,29 @@ class ManagerTest extends TestCase {
 			->method('getUID')
 			->will($this->returnValue('ferdinand'));
 
-		$this->session->expects($this->once())
+		$this->session->expects($this->at(0))
+			->method('set')
+			->with('two_factor_auth_uid', 'ferdinand');
+		$this->session->expects($this->at(1))
+			->method('set')
+			->with('two_factor_remember_login', true);
+
+		$this->manager->prepareTwoFactorLogin($this->user, true);
+	}
+
+	public function testPrepareTwoFactorLoginDontRemember() {
+		$this->user->expects($this->once())
+			->method('getUID')
+			->will($this->returnValue('ferdinand'));
+
+		$this->session->expects($this->at(0))
 			->method('set')
 			->with('two_factor_auth_uid', 'ferdinand');
+		$this->session->expects($this->at(1))
+			->method('set')
+			->with('two_factor_remember_login', false);
 
-		$this->manager->prepareTwoFactorLogin($this->user);
+		$this->manager->prepareTwoFactorLogin($this->user, false);
 	}
 
 }
diff --git a/tests/lib/User/SessionTest.php b/tests/lib/User/SessionTest.php
index 268d8e10e5a8bd553d517f399c3065783a2f2ba5..ee9ed737cf5551dd27b40c98f41d3c12149605b0 100644
--- a/tests/lib/User/SessionTest.php
+++ b/tests/lib/User/SessionTest.php
@@ -1,5 +1,4 @@
 <?php
-
 /**
  * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
  * This file is licensed under the Affero General Public License version 3 or
@@ -39,8 +38,16 @@ class SessionTest extends \Test\TestCase {
 	protected $tokenProvider;
 	/** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
 	private $config;
-	/** @var Throttler */
+	/** @var Throttler|\PHPUnit_Framework_MockObject_MockObject */
 	private $throttler;
+	/** @var ISecureRandom|\PHPUnit_Framework_MockObject_MockObject */
+	private $random;
+	/** @var IUserManager|\PHPUnit_Framework_MockObject_MockObject */
+	private $manager;
+	/** @var ISession|\PHPUnit_Framework_MockObject_MockObject */
+	private $session;
+	/** @var Session|\PHPUnit_Framework_MockObject_MockObject */
+	private $userSession;
 
 	protected function setUp() {
 		parent::setUp();
@@ -52,6 +59,24 @@ class SessionTest extends \Test\TestCase {
 		$this->tokenProvider = $this->createMock(IProvider::class);
 		$this->config = $this->createMock(IConfig::class);
 		$this->throttler = $this->createMock(Throttler::class);
+		$this->random = $this->createMock(ISecureRandom::class);
+		$this->manager = $this->createMock(IUserManager::class);
+		$this->session = $this->createMock(ISession::class);
+		$this->userSession = $this->getMockBuilder(Session::class)
+			->setConstructorArgs([
+				$this->manager,
+				$this->session,
+				$this->timeFactory,
+				$this->tokenProvider,
+				$this->config,
+				$this->random,
+			])
+			->setMethods([
+				'setMagicInCookie',
+			])
+			->getMock();
+
+		\OC_User::setIncognitoMode(false);
 	}
 
 	public function testGetUser() {
@@ -100,12 +125,12 @@ class SessionTest extends \Test\TestCase {
 			->method('updateTokenActivity')
 			->with($token);
 
-		$manager->expects($this->any())
+		$manager->expects($this->once())
 			->method('get')
 			->with($expectedUser->getUID())
 			->will($this->returnValue($expectedUser));
 
-		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random);
 		$user = $userSession->getUser();
 		$this->assertSame($expectedUser, $user);
 		$this->assertSame(10000, $token->getLastCheck());
@@ -127,7 +152,7 @@ class SessionTest extends \Test\TestCase {
 		$manager = $this->createMock(Manager::class);
 
 		$userSession = $this->getMockBuilder(Session::class)
-			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
 			->setMethods([
 				'getUser'
 			])
@@ -154,7 +179,7 @@ class SessionTest extends \Test\TestCase {
 			->method('getUID')
 			->will($this->returnValue('foo'));
 
-		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random);
 		$userSession->setUser($user);
 	}
 
@@ -181,17 +206,10 @@ class SessionTest extends \Test\TestCase {
 			}, 'foo'));
 
 		$managerMethods = get_class_methods(Manager::class);
-		//keep following methods intact in order to ensure hooks are
-		//working
-		$doNotMock = array('__construct', 'emit', 'listen');
-		foreach ($doNotMock as $methodName) {
-			$i = array_search($methodName, $managerMethods, true);
-			if ($i !== false) {
-				unset($managerMethods[$i]);
-			}
-		}
+		//keep following methods intact in order to ensure hooks are working
+		$mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
 		$manager = $this->getMockBuilder(Manager::class)
-			->setMethods($managerMethods)
+			->setMethods($mockedManagerMethods)
 			->setConstructorArgs([$this->config])
 			->getMock();
 
@@ -213,7 +231,7 @@ class SessionTest extends \Test\TestCase {
 			->will($this->returnValue($user));
 
 		$userSession = $this->getMockBuilder(Session::class)
-			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
 			->setMethods([
 				'prepareUserLogin'
 			])
@@ -238,18 +256,11 @@ class SessionTest extends \Test\TestCase {
 			->with('bar')
 			->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));
 
-		$managerMethods = get_class_methods('\OC\User\Manager');
-		//keep following methods intact in order to ensure hooks are
-		//working
-		$doNotMock = array('__construct', 'emit', 'listen');
-		foreach ($doNotMock as $methodName) {
-			$i = array_search($methodName, $managerMethods, true);
-			if ($i !== false) {
-				unset($managerMethods[$i]);
-			}
-		}
+		$managerMethods = get_class_methods(\OC\User\Manager::class);
+		//keep following methods intact in order to ensure hooks are working
+		$mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
 		$manager = $this->getMockBuilder(Manager::class)
-			->setMethods($managerMethods)
+			->setMethods($mockedManagerMethods)
 			->setConstructorArgs([$this->config])
 			->getMock();
 
@@ -267,28 +278,21 @@ class SessionTest extends \Test\TestCase {
 			->with('foo', 'bar')
 			->will($this->returnValue($user));
 
-		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random);
 		$userSession->login('foo', 'bar');
 	}
 
 	public function testLoginInvalidPassword() {
 		$session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
-		$managerMethods = get_class_methods('\OC\User\Manager');
-		//keep following methods intact in order to ensure hooks are
-		//working
-		$doNotMock = array('__construct', 'emit', 'listen');
-		foreach ($doNotMock as $methodName) {
-			$i = array_search($methodName, $managerMethods, true);
-			if ($i !== false) {
-				unset($managerMethods[$i]);
-			}
-		}
+		$managerMethods = get_class_methods(\OC\User\Manager::class);
+		//keep following methods intact in order to ensure hooks are working
+		$mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
 		$manager = $this->getMockBuilder(Manager::class)
-			->setMethods($managerMethods)
+			->setMethods($mockedManagerMethods)
 			->setConstructorArgs([$this->config])
 			->getMock();
 		$backend = $this->createMock(\Test\Util\User\Dummy::class);
-		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random);
 
 		$user = $this->getMockBuilder(User::class)->setConstructorArgs(['foo', $backend])->getMock();
 
@@ -317,7 +321,7 @@ class SessionTest extends \Test\TestCase {
 	public function testLoginNonExisting() {
 		$session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
 		$manager = $this->createMock(Manager::class);
-		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random);
 
 		$session->expects($this->never())
 			->method('set');
@@ -343,7 +347,7 @@ class SessionTest extends \Test\TestCase {
 	public function testLoginWithDifferentTokenLoginName() {
 		$session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
 		$manager = $this->createMock(Manager::class);
-		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random);
 		$username = 'user123';
 		$token = new \OC\Authentication\Token\DefaultToken();
 		$token->setLoginName($username);
@@ -375,7 +379,7 @@ class SessionTest extends \Test\TestCase {
 
 		/** @var \OC\User\Session $userSession */
 		$userSession = $this->getMockBuilder(Session::class)
-			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
 			->setMethods(['login', 'supportsCookies', 'createSessionToken', 'getUser'])
 			->getMock();
 
@@ -411,7 +415,7 @@ class SessionTest extends \Test\TestCase {
 
 		/** @var Session $userSession */
 		$userSession = $this->getMockBuilder(Session::class)
-			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
 			->setMethods(['login', 'supportsCookies', 'createSessionToken', 'getUser'])
 			->getMock();
 
@@ -434,7 +438,7 @@ class SessionTest extends \Test\TestCase {
 
 		/** @var \OC\User\Session $userSession */
 		$userSession = $this->getMockBuilder(Session::class)
-			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
 			->setMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser'])
 			->getMock();
 
@@ -476,7 +480,7 @@ class SessionTest extends \Test\TestCase {
 
 		/** @var \OC\User\Session $userSession */
 		$userSession = $this->getMockBuilder(Session::class)
-			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
 			->setMethods(['login', 'isTwoFactorEnforced'])
 			->getMock();
 
@@ -513,156 +517,216 @@ class SessionTest extends \Test\TestCase {
 
 	public function testRememberLoginValidToken() {
 		$session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
-		$session->expects($this->exactly(1))
-			->method('set')
-			->with($this->callback(function ($key) {
-				switch ($key) {
-					case 'user_id':
-						return true;
-					default:
-						return false;
-				}
-			}, 'foo'));
-		$session->expects($this->once())
-			->method('regenerateId');
-
-		$managerMethods = get_class_methods(Manager::class);
-		//keep following methods intact in order to ensure hooks are
-		//working
-		$doNotMock = array('__construct', 'emit', 'listen');
-		foreach ($doNotMock as $methodName) {
-			$i = array_search($methodName, $managerMethods, true);
-			if ($i !== false) {
-				unset($managerMethods[$i]);
-			}
-		}
+		$managerMethods = get_class_methods(\OC\User\Manager::class);
+		//keep following methods intact in order to ensure hooks are working
+		$mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
 		$manager = $this->getMockBuilder(Manager::class)
-			->setMethods($managerMethods)
+			->setMethods($mockedManagerMethods)
 			->setConstructorArgs([$this->config])
 			->getMock();
+		$userSession = $this->getMockBuilder(Session::class)
+			//override, otherwise tests will fail because of setcookie()
+			->setMethods(['setMagicInCookie'])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
+			->getMock();
 
-		$backend = $this->createMock(\Test\Util\User\Dummy::class);
+		$user = $this->createMock(IUser::class);
+		$token = 'goodToken';
+		$oldSessionId = 'sess321';
+		$sessionId = 'sess123';
 
-		$user = $this->getMockBuilder(User::class)->setConstructorArgs(['foo', $backend])->getMock();
+		$session->expects($this->once())
+			->method('regenerateId');
+		$manager->expects($this->once())
+			->method('get')
+			->with('foo')
+			->will($this->returnValue($user));
+		$this->config->expects($this->once())
+			->method('getUserKeys')
+			->with('foo', 'login_token')
+			->will($this->returnValue([$token]));
+		$this->config->expects($this->once())
+			->method('deleteUserValue')
+			->with('foo', 'login_token', $token);
+		$this->random->expects($this->once())
+			->method('generate')
+			->with(32)
+			->will($this->returnValue('abcdefg123456'));
+		$this->config->expects($this->once())
+			->method('setUserValue')
+			->with('foo', 'login_token', 'abcdefg123456', 10000);
+
+		$session->expects($this->once())
+			->method('getId')
+			->will($this->returnValue($sessionId));
+		$this->tokenProvider->expects($this->once())
+			->method('renewSessionToken')
+			->with($oldSessionId, $sessionId)
+			->will($this->returnValue(true));
 
 		$user->expects($this->any())
 			->method('getUID')
 			->will($this->returnValue('foo'));
+		$userSession->expects($this->once())
+			->method('setMagicInCookie');
 		$user->expects($this->once())
 			->method('updateLastLoginTimestamp');
+		$session->expects($this->once())
+			->method('set')
+			->with('user_id', 'foo');
 
-		$manager->expects($this->once())
-			->method('get')
-			->with('foo')
-			->will($this->returnValue($user));
+		$granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
 
-		//prepare login token
-		$token = 'goodToken';
-		\OC::$server->getConfig()->setUserValue('foo', 'login_token', $token, time());
+		$this->assertTrue($granted);
+	}
 
+	public function testRememberLoginInvalidSessionToken() {
+		$session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
+		$managerMethods = get_class_methods(\OC\User\Manager::class);
+		//keep following methods intact in order to ensure hooks are working
+		$mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
+		$manager = $this->getMockBuilder(Manager::class)
+			->setMethods($mockedManagerMethods)
+			->setConstructorArgs([$this->config])
+			->getMock();
 		$userSession = $this->getMockBuilder(Session::class)
 			//override, otherwise tests will fail because of setcookie()
 			->setMethods(['setMagicInCookie'])
-			//there  are passed as parameters to the constructor
-			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
 			->getMock();
 
-		$granted = $userSession->loginWithCookie('foo', $token);
-
-		$this->assertSame($granted, true);
-	}
+		$user = $this->createMock(IUser::class);
+		$token = 'goodToken';
+		$oldSessionId = 'sess321';
+		$sessionId = 'sess123';
 
-	public function testRememberLoginInvalidToken() {
-		$session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
-		$session->expects($this->never())
-			->method('set');
 		$session->expects($this->once())
 			->method('regenerateId');
+		$manager->expects($this->once())
+			->method('get')
+			->with('foo')
+			->will($this->returnValue($user));
+		$this->config->expects($this->once())
+			->method('getUserKeys')
+			->with('foo', 'login_token')
+			->will($this->returnValue([$token]));
+		$this->config->expects($this->once())
+			->method('deleteUserValue')
+			->with('foo', 'login_token', $token);
+		$this->config->expects($this->once())
+			->method('setUserValue'); // TODO: mock new random value
 
-		$managerMethods = get_class_methods('\OC\User\Manager');
-		//keep following methods intact in order to ensure hooks are
-		//working
-		$doNotMock = array('__construct', 'emit', 'listen');
-		foreach ($doNotMock as $methodName) {
-			$i = array_search($methodName, $managerMethods, true);
-			if ($i !== false) {
-				unset($managerMethods[$i]);
-			}
-		}
-		$manager = $this->getMockBuilder(Manager::class)
-			->setMethods($managerMethods)
-			->setConstructorArgs([$this->config])
-			->getMock();
-
-		$backend = $this->createMock(\Test\Util\User\Dummy::class);
-
-		$user = $this->getMockBuilder(User::class)->setConstructorArgs(['foo', $backend])->getMock();
+		$session->expects($this->once())
+			->method('getId')
+			->will($this->returnValue($sessionId));
+		$this->tokenProvider->expects($this->once())
+			->method('renewSessionToken')
+			->with($oldSessionId, $sessionId)
+			->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));
 
-		$user->expects($this->any())
+		$user->expects($this->never())
 			->method('getUID')
 			->will($this->returnValue('foo'));
+		$userSession->expects($this->never())
+			->method('setMagicInCookie');
 		$user->expects($this->never())
 			->method('updateLastLoginTimestamp');
+		$session->expects($this->never())
+			->method('set')
+			->with('user_id', 'foo');
 
+		$granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
+
+		$this->assertFalse($granted);
+	}
+
+	public function testRememberLoginInvalidToken() {
+		$session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
+		$managerMethods = get_class_methods(\OC\User\Manager::class);
+		//keep following methods intact in order to ensure hooks are working
+		$mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
+		$manager = $this->getMockBuilder(Manager::class)
+			->setMethods($mockedManagerMethods)
+			->setConstructorArgs([$this->config])
+			->getMock();
+		$userSession = $this->getMockBuilder(Session::class)
+			//override, otherwise tests will fail because of setcookie()
+			->setMethods(['setMagicInCookie'])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
+			->getMock();
+
+		$user = $this->createMock(IUser::class);
+		$token = 'goodToken';
+		$oldSessionId = 'sess321';
+
+		$session->expects($this->once())
+			->method('regenerateId');
 		$manager->expects($this->once())
 			->method('get')
 			->with('foo')
 			->will($this->returnValue($user));
+		$this->config->expects($this->once())
+			->method('getUserKeys')
+			->with('foo', 'login_token')
+			->will($this->returnValue(['anothertoken']));
+		$this->config->expects($this->never())
+			->method('deleteUserValue')
+			->with('foo', 'login_token', $token);
+
+		$this->tokenProvider->expects($this->never())
+			->method('renewSessionToken');
+		$userSession->expects($this->never())
+			->method('setMagicInCookie');
+		$user->expects($this->never())
+			->method('updateLastLoginTimestamp');
+		$session->expects($this->never())
+			->method('set')
+			->with('user_id', 'foo');
 
-		//prepare login token
-		$token = 'goodToken';
-		\OC::$server->getConfig()->setUserValue('foo', 'login_token', $token, time());
-
-		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
-		$granted = $userSession->loginWithCookie('foo', 'badToken');
+		$granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
 
-		$this->assertSame($granted, false);
+		$this->assertFalse($granted);
 	}
 
 	public function testRememberLoginInvalidUser() {
 		$session = $this->getMockBuilder(Memory::class)->setConstructorArgs([''])->getMock();
-		$session->expects($this->never())
-			->method('set');
-		$session->expects($this->once())
-			->method('regenerateId');
-
-		$managerMethods = get_class_methods('\OC\User\Manager');
-		//keep following methods intact in order to ensure hooks are
-		//working
-		$doNotMock = array('__construct', 'emit', 'listen');
-		foreach ($doNotMock as $methodName) {
-			$i = array_search($methodName, $managerMethods, true);
-			if ($i !== false) {
-				unset($managerMethods[$i]);
-			}
-		}
+		$managerMethods = get_class_methods(\OC\User\Manager::class);
+		//keep following methods intact in order to ensure hooks are working
+		$mockedManagerMethods = array_diff($managerMethods, ['__construct', 'emit', 'listen']);
 		$manager = $this->getMockBuilder(Manager::class)
-			->setMethods($managerMethods)
+			->setMethods($mockedManagerMethods)
 			->setConstructorArgs([$this->config])
 			->getMock();
+		$userSession = $this->getMockBuilder(Session::class)
+			//override, otherwise tests will fail because of setcookie()
+			->setMethods(['setMagicInCookie'])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
+			->getMock();
+		$token = 'goodToken';
+		$oldSessionId = 'sess321';
 
-		$backend = $this->createMock(\Test\Util\User\Dummy::class);
-
-		$user = $this->getMockBuilder(User::class)->setConstructorArgs(['foo', $backend])->getMock();
-
-		$user->expects($this->never())
-			->method('getUID');
-		$user->expects($this->never())
-			->method('updateLastLoginTimestamp');
-
+		$session->expects($this->once())
+			->method('regenerateId');
 		$manager->expects($this->once())
 			->method('get')
 			->with('foo')
 			->will($this->returnValue(null));
+		$this->config->expects($this->never())
+			->method('getUserKeys')
+			->with('foo', 'login_token')
+			->will($this->returnValue(['anothertoken']));
+
+		$this->tokenProvider->expects($this->never())
+			->method('renewSessionToken');
+		$userSession->expects($this->never())
+			->method('setMagicInCookie');
+		$session->expects($this->never())
+			->method('set')
+			->with('user_id', 'foo');
 
-		//prepare login token
-		$token = 'goodToken';
-		\OC::$server->getConfig()->setUserValue('foo', 'login_token', $token, time());
-
-		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
-		$granted = $userSession->loginWithCookie('foo', $token);
+		$granted = $userSession->loginWithCookie('foo', $token, $oldSessionId);
 
-		$this->assertSame($granted, false);
+		$this->assertFalse($granted);
 	}
 
 	public function testActiveUserAfterSetSession() {
@@ -684,7 +748,7 @@ class SessionTest extends \Test\TestCase {
 		$session = new Memory('');
 		$session->set('user_id', 'foo');
 		$userSession = $this->getMockBuilder('\OC\User\Session')
-			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
 			->setMethods([
 				'validateSession'
 			])
@@ -705,7 +769,7 @@ class SessionTest extends \Test\TestCase {
 		$session = $this->createMock(ISession::class);
 		$token = $this->createMock(IToken::class);
 		$user = $this->createMock(IUser::class);
-		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random);
 
 		$random = $this->createMock(ISecureRandom::class);
 		$config = $this->createMock(IConfig::class);
@@ -749,7 +813,7 @@ class SessionTest extends \Test\TestCase {
 		$session = $this->createMock(ISession::class);
 		$token = $this->createMock(IToken::class);
 		$user = $this->createMock(IUser::class);
-		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random);
 
 		$random = $this->createMock(ISecureRandom::class);
 		$config = $this->createMock(IConfig::class);
@@ -796,7 +860,7 @@ class SessionTest extends \Test\TestCase {
 			->disableOriginalConstructor()
 			->getMock();
 		$session = $this->createMock(ISession::class);
-		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random);
 		$request = $this->createMock(IRequest::class);
 
 		$uid = 'user123';
@@ -826,7 +890,7 @@ class SessionTest extends \Test\TestCase {
 		$user = $this->createMock(IUser::class);
 		$userSession = $this->getMockBuilder('\OC\User\Session')
 			->setMethods(['logout'])
-			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
+			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random])
 			->getMock();
 		$request = $this->createMock(IRequest::class);
 
@@ -855,7 +919,7 @@ class SessionTest extends \Test\TestCase {
 		$timeFactory = $this->createMock(ITimeFactory::class);
 		$tokenProvider = $this->createMock(IProvider::class);
 		$userSession = $this->getMockBuilder('\OC\User\Session')
-			->setConstructorArgs([$userManager, $session, $timeFactory, $tokenProvider, $this->config])
+			->setConstructorArgs([$userManager, $session, $timeFactory, $tokenProvider, $this->config, $this->random])
 			->setMethods(['logout'])
 			->getMock();
 
@@ -902,7 +966,7 @@ class SessionTest extends \Test\TestCase {
 		$timeFactory = $this->createMock(ITimeFactory::class);
 		$tokenProvider = $this->createMock(IProvider::class);
 		$userSession = $this->getMockBuilder('\OC\User\Session')
-			->setConstructorArgs([$userManager, $session, $timeFactory, $tokenProvider, $this->config])
+			->setConstructorArgs([$userManager, $session, $timeFactory, $tokenProvider, $this->config, $this->random])
 			->setMethods(['logout'])
 			->getMock();
 
@@ -936,7 +1000,7 @@ class SessionTest extends \Test\TestCase {
 		$session = $this->createMock(ISession::class);
 		$timeFactory = $this->createMock(ITimeFactory::class);
 		$tokenProvider = $this->createMock(IProvider::class);
-		$userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config, $this->random);
 
 		$password = '123456';
 		$sessionId = 'session1234';
@@ -961,7 +1025,7 @@ class SessionTest extends \Test\TestCase {
 		$session = $this->createMock(ISession::class);
 		$timeFactory = $this->createMock(ITimeFactory::class);
 		$tokenProvider = $this->createMock(IProvider::class);
-		$userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config, $this->random);
 
 		$session->expects($this->once())
 			->method('getId')
@@ -975,7 +1039,7 @@ class SessionTest extends \Test\TestCase {
 		$session = $this->createMock(ISession::class);
 		$timeFactory = $this->createMock(ITimeFactory::class);
 		$tokenProvider = $this->createMock(IProvider::class);
-		$userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config);
+		$userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config, $this->random);
 
 		$password = '123456';
 		$sessionId = 'session1234';
@@ -1015,7 +1079,7 @@ class SessionTest extends \Test\TestCase {
 		$tokenProvider = new DefaultTokenProvider($mapper, $crypto, $this->config, $logger, $this->timeFactory);
 
 		/** @var \OC\User\Session $userSession */
-		$userSession = new Session($manager, $session, $this->timeFactory, $tokenProvider, $this->config);
+		$userSession = new Session($manager, $session, $this->timeFactory, $tokenProvider, $this->config, $this->random);
 
 		$mapper->expects($this->any())
 			->method('getToken')
@@ -1065,7 +1129,7 @@ class SessionTest extends \Test\TestCase {
 		$tokenProvider = new DefaultTokenProvider($mapper, $crypto, $this->config, $logger, $this->timeFactory);
 
 		/** @var \OC\User\Session $userSession */
-		$userSession = new Session($manager, $session, $this->timeFactory, $tokenProvider, $this->config);
+		$userSession = new Session($manager, $session, $this->timeFactory, $tokenProvider, $this->config, $this->random);
 
 		$mapper->expects($this->any())
 			->method('getToken')
@@ -1092,4 +1156,27 @@ class SessionTest extends \Test\TestCase {
 
 		$userSession->logClientIn('john', 'doe', $request, $this->throttler);
 	}
+
+	public function testCreateRememberMeToken() {
+		$user = $this->createMock(IUser::class);
+		$user
+			->expects($this->exactly(2))
+			->method('getUID')
+			->willReturn('UserUid');
+		$this->random
+			->expects($this->once())
+			->method('generate')
+			->with(32)
+			->willReturn('LongRandomToken');
+		$this->config
+			->expects($this->once())
+			->method('setUserValue')
+			->with('UserUid', 'login_token', 'LongRandomToken', 10000);
+		$this->userSession
+			->expects($this->once())
+			->method('setMagicInCookie')
+			->with('UserUid', 'LongRandomToken');
+
+		$this->userSession->createRememberMeToken($user);
+	}
 }
diff --git a/version.php b/version.php
index 96725a6bb4dda36b876011d9c4520865ce7cb4e2..e6de2e2bde0cc2257020cc59bcc18a22ecbae835 100644
--- a/version.php
+++ b/version.php
@@ -25,7 +25,7 @@
 // We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades
 // between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
 // when updating major/minor version number.
-$OC_Version = array(9, 2, 0, 4);
+$OC_Version = array(9, 2, 0, 5);
 
 // The human readable string
 $OC_VersionString = '11.0 alpha';