diff --git a/docs/simplesamlphp-upgrade-notes-1.14.txt b/docs/simplesamlphp-upgrade-notes-1.14.txt
index a0fcb727d762d27c09cbc169aa2d367deb471c08..7848b07c69d248f47d1d6d5acc03a9b3c33ac6ce 100644
--- a/docs/simplesamlphp-upgrade-notes-1.14.txt
+++ b/docs/simplesamlphp-upgrade-notes-1.14.txt
@@ -88,6 +88,7 @@ The following methods and classes have been deprecated. Refer to the code for al
     * `SimpleSAML_Auth_Default`
     * `SimpleSAML_Auth_Default::extractPersistentAuthState()`
     * `SimpleSAML_Auth_Default::handleUnsolicitedAuth()`
+    * `SimpleSAML_Auth_Default::loginCompleted()`
     * `SimpleSAML_Utilities`
     * `SimpleSAML_Utilities::addURLParameter()`
     * `SimpleSAML_Utilities::aesDecrypt()`
diff --git a/lib/SimpleSAML/Auth/Default.php b/lib/SimpleSAML/Auth/Default.php
index ca28cb2f147ebd3cf2736d8067446e240290df01..605825dab0a551b0e9b30135fb4777c9b1012797 100644
--- a/lib/SimpleSAML/Auth/Default.php
+++ b/lib/SimpleSAML/Auth/Default.php
@@ -87,9 +87,7 @@ class SimpleSAML_Auth_Default {
 
 
 	/**
-	 * Called when a login operation has finished.
-	 *
-	 * @param array $state  The state after the login.
+	 * @deprecated This method will be removed in SSP 2.0.
 	 */
 	public static function loginCompleted($state) {
 		assert('is_array($state)');
diff --git a/lib/SimpleSAML/Auth/Source.php b/lib/SimpleSAML/Auth/Source.php
index 4f071fa71e0a4a5444218ef3a437736f637017ab..9f45a607ec95925b2fd74aa51100422738eb2c99 100644
--- a/lib/SimpleSAML/Auth/Source.php
+++ b/lib/SimpleSAML/Auth/Source.php
@@ -147,6 +147,38 @@ abstract class SimpleSAML_Auth_Source
     }
 
 
+    /**
+     * Called when a login operation has finished.
+     *
+     * This method never returns.
+     *
+     * @param array $state The state after the login has completed.
+     */
+    protected static function loginCompleted($state)
+    {
+        assert('is_array($state)');
+        assert('array_key_exists("SimpleSAML_Auth_Default.Return", $state)');
+        assert('array_key_exists("SimpleSAML_Auth_Default.id", $state)');
+        assert('array_key_exists("Attributes", $state)');
+        assert('!array_key_exists("LogoutState", $state) || is_array($state["LogoutState"])');
+
+        $return = $state['SimpleSAML_Auth_Default.Return'];
+
+        // save session state
+        $session = SimpleSAML_Session::getSessionFromRequest();
+        $authId = $state['SimpleSAML_Auth_Default.id'];
+        $state = SimpleSAML_Auth_State::extractPersistentAuthState($state);
+        $session->doLogin($authId, $state);
+
+        if (is_string($return)) { // redirect...
+            \SimpleSAML\Utils\HTTP::redirectTrustedURL($return);
+        } else {
+            call_user_func($return, $state);
+        }
+        assert('false');
+    }
+
+
     /**
      * Log out from this authentication source.
      *