diff --git a/core/authorize.php b/core/authorize.php
index f347ba5..e3f5caf 100644
--- a/core/authorize.php
+++ b/core/authorize.php
@@ -65,7 +65,7 @@ function authorize_access_allowed() {
 
 // We prepare only a minimal bootstrap. This includes the database and
 // variables, however, so we have access to the class autoloader.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
+drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
 
 // This must go after drupal_bootstrap(), which unsets globals!
 global $conf;
diff --git a/core/core.services.yml b/core/core.services.yml
index e49da7f..9a91764 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -452,3 +452,22 @@ services:
   date:
     class: Drupal\Core\Datetime\Date
     arguments: ['@config.factory', '@language_manager']
+  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 }
+    arguments: ['@authentication']
+  access_check.authentication_provider:
+    class: Drupal\Core\Access\AuthenticationProviderAccessCheck
+    tags:
+      - { name: access_check }
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index a2fea5c..a88639c 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -158,11 +158,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;
@@ -1762,7 +1757,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.
@@ -1781,7 +1775,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,
   );
@@ -1831,11 +1824,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..5ab0961
--- /dev/null
+++ b/core/lib/Drupal/Core/Access/AuthenticationProviderAccessCheck.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Access\AuthenticationProviderAccessCheck.
+ */
+
+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) {
+    $auth_provider_triggered = $request->attributes->get('_authentication_provider');
+    if (!empty($auth_provider_triggered)) {
+      $allowed_auth_providers = $route->getOption('_auth') ?: array('cookie');
+      return in_array($auth_provider_triggered, $allowed_auth_providers);
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
new file mode 100644
index 0000000..dc1da08
--- /dev/null
+++ b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Authentication\AuthenticationManager.
+ */
+
+namespace Drupal\Core\Authentication;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
+
+class AuthenticationManager implements AuthenticationProviderInterface {
+
+  /**
+   * Array of all registered authentication providers.
+   *
+   * @var AuthenticationProviderInterface[]
+   */
+  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 by running autheticate() method on each of providers.
+   *
+   * @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;
+      }
+    }
+
+    // Cookie provider initialize anonymous user by default, so if no other providers
+    // authenticated request we treat it as authenticated by cookie.
+    if (empty($this->triggered_provider)) {
+      $this->triggered_provider = 'authentication.cookie';
+    }
+    // Save id of provider to request so it is checked in AuthenticationProviderAccessCheck.
+    $request->attributes->set('_authentication_provider', substr($this->triggered_provider, strlen('authentication.')));
+  }
+
+  /**
+   * Does clean up by running cleanup() of 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);
+  }
+}
diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationProviderInterface.php b/core/lib/Drupal/Core/Authentication/AuthenticationProviderInterface.php
new file mode 100644
index 0000000..a44a210
--- /dev/null
+++ b/core/lib/Drupal/Core/Authentication/AuthenticationProviderInterface.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Authentication\AuthenticationProviderInterface.
+ */
+
+namespace Drupal\Core\Authentication;
+
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Interface for authentication providers.
+ */
+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);
+}
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..57e33f9
--- /dev/null
+++ b/core/lib/Drupal/Core/Authentication/Provider/Cookie.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Authentication\Provider\Cookie.
+ */
+
+namespace Drupal\Core\Authentication\Provider;
+
+use Drupal\Core\Authentication\AuthenticationProviderInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Cookie based authentication provider.
+ */
+class Cookie implements AuthenticationProviderInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  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;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function cleanup(Request $request) {
+    drupal_session_commit();
+  }
+}
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..0992f52
--- /dev/null
+++ b/core/lib/Drupal/Core/Authentication/Provider/HttpBasic.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Authentication\Provider\HttpBasic.
+ */
+
+namespace Drupal\Core\Authentication\Provider;
+
+use Drupal\Core\Authentication\AuthenticationProviderInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * HTTP Basic authentication provider.
+ */
+class HttpBasic implements AuthenticationProviderInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function authenticate(Request $request) {
+    $username = $request->headers->get('PHP_AUTH_USER');
+    $password = $request->headers->get('PHP_AUTH_PW');
+    if ($username && $password) {
+      $uid = user_authenticate($username, $password);
+      if ($uid) {
+        global $user;
+        $user = user_load($uid);
+        return TRUE;
+      }
+      return FALSE;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function cleanup(Request $request) {}
+}
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 472105a..3e6147b 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -17,6 +17,7 @@
 use Drupal\Core\DependencyInjection\Compiler\RegisterParamConvertersPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterServicesForDestructionPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterStringTranslatorsPass;
+use Drupal\Core\DependencyInjection\Compiler\RegisterAuthenticationPass;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\DependencyInjection\Reference;
@@ -63,6 +64,8 @@ public function build(ContainerBuilder $container) {
     $container->addCompilerPass(new ListCacheBinsPass());
     // Add the compiler pass for appending string translators.
     $container->addCompilerPass(new RegisterStringTranslatorsPass());
+    // 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..243d49b
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/RegisterAuthenticationPass.php
@@ -0,0 +1,31 @@
+<?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 {
+
+  /**
+   * {@inheritdoc}
+   */
+  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..de53505
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/AuthenticationSubscriber.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\EventSubscriber\AuthenticationSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Drupal\Core\Authentication\AuthenticationProviderInterface;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+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 implements EventSubscriberInterface {
+
+  /**
+   * Authentication manager.
+   *
+   * @var AuthenticationProviderInterface
+   */
+  private $authentication_manager;
+
+  /**
+   * Keep authentication manager as private variable.
+   *
+   * @param AuthenticationProviderInterface $authentication_manager
+   */
+  public function __construct(AuthenticationProviderInterface $authentication_manager) {
+    $this->authentication_manager = $authentication_manager;
+  }
+
+  /**
+   * Authenticate user
+   *
+   * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+   *   The Event to process.
+   */
+  public function onKernelRequestAuthenticate(GetResponseEvent $event) {
+    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
+      $request = $event->getRequest();
+      $this->authentication_manager->authenticate($request);
+    }
+  }
+
+  public function onRespond(FilterResponseEvent $event) {
+    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
+      $request = $event->getRequest();
+
+      $this->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 0b9bbad..98eef05 100644
--- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
@@ -91,8 +91,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 processing and we intend to
     //   use partial page caching more extensively.
-    // Commit the user session, if needed.
-    drupal_session_commit();
 
     // Attach globally-declared headers to the response object so that Symfony
     // can send them for us correctly.
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index d3ba7b3..975788a 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -876,6 +876,7 @@ protected function prepareEnvironment() {
     $this->originalUser = isset($user) ? clone $user : NULL;
 
     // Ensure that the current session is not changed by the new environment.
+    require_once DRUPAL_ROOT . '/' . settings()->get('session_inc', 'core/includes/session.inc');
     drupal_save_session(FALSE);
     // Run all tests as a anonymous user by default, web tests will replace that
     // during the test set up.
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..95a5483
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Authentication/HttpBasicTest.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\system\Tests\Authentication\HttpBasicTest.
+ */
+
+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',
+    );
+  }
+
+  /**
+   * Test http basic 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;
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
index b613121..9de96b0 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
@@ -93,6 +93,10 @@ protected function setUp() {
     // Load the Update API.
     require_once DRUPAL_ROOT . '/core/includes/update.inc';
 
+    // Load Session API.
+    require_once DRUPAL_ROOT . '/core/includes/session.inc';
+    drupal_session_initialize();
+
     // Reset flags.
     $this->upgradedSite = FALSE;
     $this->upgradeErrors = array();
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..9e481de 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'
diff --git a/core/update.php b/core/update.php
index a3dd4bb..921dd81 100644
--- a/core/update.php
+++ b/core/update.php
@@ -427,7 +427,9 @@ function update_check_requirements($skip_warnings = FALSE) {
 update_prepare_d8_bootstrap();
 
 // Determine if the current user has access to run update.php.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
+drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
+require_once DRUPAL_ROOT . '/' . settings()->get('session_inc', 'core/includes/session.inc');
+drupal_session_initialize();
 
 // A request object from the HTTPFoundation to tell us about the request.
 // @todo These two lines were copied from index.php which has its own todo about
