diff --git a/core/core.services.yml b/core/core.services.yml
index 55d5b34..38abcef 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -427,3 +427,23 @@ services:
   batch.storage:
     class: Drupal\Core\Utility\BatchStorage
     arguments: ['@database']
+  authentication:
+    class: Drupal\Core\Authentication\AuthenticationManager
+  authentication.cookie:
+    class: Drupal\Core\Authentication\Provider\Cookie
+    tags:
+      - { name: authentication_provider }
+  authentication.http_basic:
+    class: Drupal\Core\Authentication\Provider\HttpBasic
+    tags:
+      - { name: authentication_provider }
+  authentication_subscriber:
+    class: Drupal\Core\EventSubscriber\AuthenticationSubscriber
+    tags:
+      - { name: event_subscriber }
+    calls:
+      - [setContainer, ['@service_container']]
+  access_check.authentication_provider:
+    class: Drupal\Core\Access\AuthenticationProviderAccessCheck
+    tags:
+      - { name: access_check }
\ No newline at end of file
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 4c9df06..faf22bd 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -156,11 +156,6 @@
 const DRUPAL_BOOTSTRAP_VARIABLES = 4;
 
 /**
- * Sixth bootstrap phase: initialize session handling.
- */
-const DRUPAL_BOOTSTRAP_SESSION = 5;
-
-/**
  * Eighth bootstrap phase: load code for subsystems and modules.
  */
 const DRUPAL_BOOTSTRAP_CODE = 6;
@@ -1787,7 +1782,6 @@ function drupal_anonymous_user() {
  *   - DRUPAL_BOOTSTRAP_PAGE_CACHE: Tries to serve a cached page.
  *   - DRUPAL_BOOTSTRAP_DATABASE: Initializes the database layer.
  *   - DRUPAL_BOOTSTRAP_VARIABLES: Initializes the variable system.
- *   - DRUPAL_BOOTSTRAP_SESSION: Initializes session handling.
  *   - DRUPAL_BOOTSTRAP_CODE: Loads code for subsystems and modules.
  *   - DRUPAL_BOOTSTRAP_FULL: Fully loads Drupal. Validates and fixes input
  *     data.
@@ -1806,7 +1800,6 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
     DRUPAL_BOOTSTRAP_PAGE_CACHE,
     DRUPAL_BOOTSTRAP_DATABASE,
     DRUPAL_BOOTSTRAP_VARIABLES,
-    DRUPAL_BOOTSTRAP_SESSION,
     DRUPAL_BOOTSTRAP_CODE,
     DRUPAL_BOOTSTRAP_FULL,
   );
@@ -1856,11 +1849,6 @@ function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
           _drupal_bootstrap_variables();
           break;
 
-        case DRUPAL_BOOTSTRAP_SESSION:
-          require_once DRUPAL_ROOT . '/' . settings()->get('session_inc', 'core/includes/session.inc');
-          drupal_session_initialize();
-          break;
-
         case DRUPAL_BOOTSTRAP_CODE:
           require_once __DIR__ . '/common.inc';
           _drupal_bootstrap_code();
diff --git a/core/lib/Drupal/Core/Access/AuthenticationProviderAccessCheck.php b/core/lib/Drupal/Core/Access/AuthenticationProviderAccessCheck.php
new file mode 100644
index 0000000..9897f83
--- /dev/null
+++ b/core/lib/Drupal/Core/Access/AuthenticationProviderAccessCheck.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Drupal\Core\Access;
+
+use Symfony\Component\Routing\Route;
+use Symfony\Component\HttpFoundation\Request;
+
+class AuthenticationProviderAccessCheck implements AccessCheckInterface {
+
+  /**
+   * This access check applies to every route.
+   *
+   * @param Route $route
+   *
+   * @return bool
+   */
+  public function applies(Route $route) {
+    return TRUE;
+  }
+
+  /**
+   * Check if route allows authentication provider.
+   *
+   * @param Route $route
+   * @param Request $request
+   *
+   * @return mixed|void
+   */
+  public function access(Route $route, Request $request) {
+    $allowed_auth_providers = $route->getOption('_auth');
+    if (empty($allowed_auth_providers)) {
+      $allowed_auth_providers = array('cookie');
+    }
+
+    $auth_provider_triggered = $request->attributes->get('_authentication_provider');
+    return in_array($auth_provider_triggered, $allowed_auth_providers);
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
new file mode 100644
index 0000000..2e8debe
--- /dev/null
+++ b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Drupal\Core\Authentication;
+
+use Drupal\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
+
+class AuthenticationManager implements AuthenticationManagerInterface {
+
+  /**
+   * Array of all registered authentication providers.
+   *
+   * @var array
+   */
+  protected $providers;
+
+  /**
+   * Id of the provider that authenticated the user.
+   *
+   * @var string
+   */
+  protected $triggered_provider = '';
+
+  /**
+   * Add provider to the array of registered providers.
+   *
+   * @param $provider_id
+   * @param AuthenticationProviderInterface $provider
+   */
+  public function addProvider($provider_id, AuthenticationProviderInterface $provider) {
+    $this->providers[$provider_id] = $provider;
+  }
+
+  /**
+   * Authenticate user using all authentication providers.
+   *
+   * @param Request $request
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+   *   Throws exception in case two authentication providers had credentials.
+   */
+  public function authenticate(Request $request) {
+
+    foreach ($this->providers as $provider_id => $provider) {
+      $result = $provider->authenticate($request);
+
+      if ($result !== NULL) {
+        // We do not allow request to have information to authenticate
+        // with two methods at the same time.
+        if (!empty($this->triggered_provider)) {
+          throw new BadRequestHttpException(t('Multiple authentication methods are not allowed.'));
+        }
+        $this->triggered_provider = $provider_id;
+
+        // Save id of provider to request so it is checked in AuthenticationProviderAccessCheck.
+        $request->attributes->set('_authentication_provider', substr($provider_id, strlen('authentication.')));
+      }
+    }
+  }
+
+  /**
+   * Run cleanup for provider that authenticated the user.
+   *
+   * @param Request $request
+   */
+  public function cleanup(Request $request) {
+    if (empty($this->triggered_provider)) {
+      return;
+    }
+    $provider = $this->providers[$this->triggered_provider];
+    $provider->cleanup($request);
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationManagerInterface.php b/core/lib/Drupal/Core/Authentication/AuthenticationManagerInterface.php
new file mode 100644
index 0000000..3aab4b7
--- /dev/null
+++ b/core/lib/Drupal/Core/Authentication/AuthenticationManagerInterface.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace Drupal\Core\Authentication;
+
+use Symfony\Component\HttpFoundation\Request;
+
+interface AuthenticationManagerInterface {
+  public function authenticate(Request $request);
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationProviderInterface.php b/core/lib/Drupal/Core/Authentication/AuthenticationProviderInterface.php
new file mode 100644
index 0000000..e8aa7cd
--- /dev/null
+++ b/core/lib/Drupal/Core/Authentication/AuthenticationProviderInterface.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\Core\Authentication;
+
+use Symfony\Component\HttpFoundation\Request;
+
+interface AuthenticationProviderInterface {
+
+  /**
+   * Authenticate user.
+   *
+   * This method called early on KernelEvents::REQUEST event.
+   *
+   * @param Request $request
+   *
+   * @return mixed
+   *   TRUE - in case we authenticated user
+   *   FALSE - in case we had credentials for authentication but user failed
+   *   NULL - no authentication credentials were found in request
+   */
+  public function authenticate(Request $request);
+
+  /**
+   * Do cleanup.
+   *
+   * This method called late on KernelEvents::RESPONSE event.
+   *
+   * @param Request $request
+   *
+   * @return mixed
+   */
+  public function cleanup(Request $request);
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Authentication/Provider/Cookie.php b/core/lib/Drupal/Core/Authentication/Provider/Cookie.php
new file mode 100644
index 0000000..e0c578b
--- /dev/null
+++ b/core/lib/Drupal/Core/Authentication/Provider/Cookie.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace Drupal\Core\Authentication\Provider;
+
+use Drupal\Core\Authentication\AuthenticationProviderInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+class Cookie implements AuthenticationProviderInterface {
+  public function authenticate(Request $request) {
+    require_once DRUPAL_ROOT . '/' . settings()->get('session_inc', 'core/includes/session.inc');
+    drupal_session_initialize();
+    if (user_is_logged_in()) {
+      return TRUE;
+    }
+  }
+
+  public function cleanup(Request $request) {
+    drupal_session_commit();
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Authentication/Provider/HttpBasic.php b/core/lib/Drupal/Core/Authentication/Provider/HttpBasic.php
new file mode 100644
index 0000000..e115b0a
--- /dev/null
+++ b/core/lib/Drupal/Core/Authentication/Provider/HttpBasic.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\Core\Authentication\Provider;
+
+use Drupal\Core\Authentication\AuthenticationProviderInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+class HttpBasic implements AuthenticationProviderInterface {
+  public function authenticate(Request $request) {
+    $username = $request->server->get('PHP_AUTH_USER');
+    $password = $request->server->get('PHP_AUTH_PW');
+    if ($username && $password) {
+      $uid = user_authenticate($username, $password);
+      if ($uid) {
+        global $user;
+        $user = user_load($uid);
+        return TRUE;
+      }
+      return FALSE;
+    }
+  }
+
+  public function cleanup(Request $request) {
+
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index d29da83..7afd234 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -16,6 +16,7 @@
 use Drupal\Core\DependencyInjection\Compiler\RegisterRouteEnhancersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterAuthenticationPass;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Reference;
@@ -60,6 +61,8 @@ public function build(ContainerBuilder $container) {
     // Add the compiler pass that will process the tagged services.
     $container->addCompilerPass(new RegisterPathProcessorsPass());
     $container->addCompilerPass(new ListCacheBinsPass());
+    // Addd the compiler pass that will process tagged authentication services.
+    $container->addCompilerPass(new RegisterAuthenticationPass());
   }
 
   /**
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterAuthenticationPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterAuthenticationPass.php
new file mode 100644
index 0000000..6a0728d
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterAuthenticationPass.php
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\DependencyInjection\Compiler\RegisterAuthenticationPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+
+/**
+ * Adds services tagged 'authentication_provider'.
+ */
+class RegisterAuthenticationPass implements CompilerPassInterface {
+
+  public function process(ContainerBuilder $container) {
+    if (!$container->hasDefinition('authentication')) {
+      return;
+    }
+    $matcher = $container->getDefinition('authentication');
+    foreach ($container->findTaggedServiceIds('authentication_provider') as $id => $attributes) {
+      $matcher->addMethodCall('addProvider', array($id, new Reference($id)));
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/EventSubscriber/AuthenticationSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/AuthenticationSubscriber.php
new file mode 100644
index 0000000..e7f8272
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/AuthenticationSubscriber.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\EventSubscriber\LegacyAccessSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\DependencyInjection\ContainerAware;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Authentication subscriber.
+ */
+class AuthenticationSubscriber extends ContainerAware implements EventSubscriberInterface {
+
+  /**
+   * Authenticate user
+   *
+   * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+   *   The Event to process.
+   */
+  public function onKernelRequestAuthenticate(GetResponseEvent $event) {
+    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
+      $authentication_manager = $this->container->get('authentication');
+      $request = $event->getRequest();
+
+      // Include sessions.inc file because
+      // core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
+      // has drupal_session_commit().
+      require_once DRUPAL_ROOT . '/' . settings()->get('session_inc', 'core/includes/session.inc');
+
+      $authentication_manager->authenticate($request);
+    }
+  }
+
+  public function onRespond(FilterResponseEvent $event) {
+    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
+      $authentication_manager = $this->container->get('authentication');
+      $request = $event->getRequest();
+
+      $authentication_manager->cleanup($request);
+    }
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onKernelRequestAuthenticate', 100);
+    $events[KernelEvents::RESPONSE][] = array('onRespond', 0);
+    return $events;
+  }
+}
diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
index 163d5c8..24d5d6f 100644
--- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
@@ -90,8 +90,6 @@ public function onRespond(FilterResponseEvent $event) {
     // @todo Revisit whether or not this is still appropriate now that the
     //   Response object does its own cache control procesisng and we intend to
     //   use partial page caching more extensively.
-    // Commit the user session, if needed.
-    drupal_session_commit();
     $max_age = config('system.performance')->get('cache.page.max_age');
     if ($max_age > 0 && ($cache = drupal_page_set_cache($response->getContent()))) {
       drupal_serve_page_from_cache($cache);
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index f07e249..c04c866 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -875,7 +875,11 @@ protected function prepareEnvironment() {
     $this->originalUser = isset($user) ? clone $user : NULL;
 
     // Ensure that the current session is not changed by the new environment.
-    drupal_save_session(FALSE);
+    // If tests are run through shell script cookie based authentication
+    // is not triggered so we do not include session.inc.
+    if (function_exists('drupal_save_session')) {
+      drupal_save_session(FALSE);
+    }
     // Run all tests as a anonymous user by default, web tests will replace that
     // during the test set up.
     $user = drupal_anonymous_user();
@@ -1070,7 +1074,11 @@ protected function tearDown() {
 
     // Restore original user session.
     $user = $this->originalUser;
-    drupal_save_session(TRUE);
+    // If tests are run using shell script cookie authentication
+    // is not triggered so we do not include session.inc file.
+    if (function_exists('drupal_save_session')) {
+      drupal_save_session(TRUE);
+    }
   }
 
   /**
diff --git a/core/modules/system/lib/Drupal/system/Tests/Authentication/HttpBasicTest.php b/core/modules/system/lib/Drupal/system/Tests/Authentication/HttpBasicTest.php
new file mode 100644
index 0000000..a6901c7
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Authentication/HttpBasicTest.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace Drupal\system\Tests\Authentication;
+
+use Drupal\Core\Authentication\Provider\HttpBasic;
+use Drupal\simpletest\WebTestBase;
+use Symfony\Component\HttpFoundation\Request;
+
+
+class HttpBasicTest extends WebTestBase {
+  public static $modules = array('router_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'HttpBasic authentication',
+      'description' => 'Tests for HttpBasic authentication provider.',
+      'group' => 'Authentication',
+    );
+  }
+
+  public function testHttpBasic() {
+    $account = $this->drupalCreateUser();
+
+    $this->basicAuthGet('router_test/test11', $account->name, $account->pass_raw);
+    $this->assertText($account->name, 'Account name should be displayed.');
+    $this->curlClose();
+
+    $this->basicAuthGet('router_test/test11', $account->name, $this->randomName());
+    $this->assertNoText($account->name, 'Bad basic auth credentials do not authenticate the user.');
+    $this->curlClose();
+
+    // Login to have a valid session.
+    $this->drupalLogin($account);
+    // This call should have both session cookies and basic authentication. So it should fail.
+    $this->basicAuthGet('router_test/test11', $account->name, $account->pass_raw);
+    $this->assertResponse('400', 'Multiple authentication methods in request lead to 400.');
+    $this->curlClose();
+
+    $this->drupalGet('router_test/test11');
+    $this->assertResponse('403', 'Not authenticated on the route that allows only http_basic.');
+  }
+
+  /**
+   * We do not use drupalGet because we need to set curl settings for basic authentication.
+   *
+   * @param string $username
+   * @param string $password
+   *
+   * @return string
+   *   Curl output.
+   */
+  protected function basicAuthGet($path, $username, $password) {
+    $out = $this->curlExec(
+      array(
+        CURLOPT_HTTPGET => TRUE,
+        CURLOPT_URL => url($path, array('absolute' => TRUE)),
+        CURLOPT_NOBODY => FALSE,
+        CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
+        CURLOPT_USERPWD => $username . ':' . $password,
+      )
+    );
+
+    $this->verbose('GET request to: ' . $path .
+      '<hr />' . $out);
+
+    return $out;
+  }
+}
\ No newline at end of file
diff --git a/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestContent.php b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestContent.php
index 56d567b..f7deee8 100644
--- a/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestContent.php
+++ b/core/modules/system/tests/modules/router_test/lib/Drupal/router_test/TestContent.php
@@ -19,4 +19,12 @@ public function test1() {
     return 'abcde';
   }
 
+  /**
+   * Provides example content for route specific authentication.
+   */
+  public function test11() {
+    global $user;
+    return $user->name;
+  }
+
 }
diff --git a/core/modules/system/tests/modules/router_test/router_test.routing.yml b/core/modules/system/tests/modules/router_test/router_test.routing.yml
index 2a989df..3ba8902 100644
--- a/core/modules/system/tests/modules/router_test/router_test.routing.yml
+++ b/core/modules/system/tests/modules/router_test/router_test.routing.yml
@@ -60,3 +60,10 @@ router_test_10:
     _content: '\Drupal\router_test\TestContent::test1'
   requirements:
     _access: 'TRUE'
+
+router_test_11:
+  pattern: '/router_test/test11'
+  options:
+    _auth: [ 'http_basic' ]
+  defaults:
+    _content: '\Drupal\router_test\TestContent::test11'
\ No newline at end of file
