diff --git a/core/core.services.yml b/core/core.services.yml
index 6f8cce6..7e668c9 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -365,6 +365,11 @@ services:
     class: Drupal\Core\EventSubscriber\LegacyAccessSubscriber
     tags:
       - { name: event_subscriber }
+  csrf_token:
+    class: Drupal\Core\Access\CsrfTokenManager
+    arguments: ['@state']
+    calls:
+      - [setRequest, ['@?request']]
   access_manager:
     class: Drupal\Core\Access\AccessManager
     calls:
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 1980f2f..5ad4dbc 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -3028,21 +3028,21 @@ function drupal_json_decode($var) {
 /**
  * Ensures the private key variable used to generate tokens is set.
  *
- * @return
+ * @return string
  *   The private key.
+ *
+ * @see \Drupal\Core\Access\CsrfTokenManager
+ *
+ * @deprecated as of Drupal 8.0. Use the csrf_token service instead.
  */
 function drupal_get_private_key() {
-  if (!($key = Drupal::state()->get('system.private_key'))) {
-    $key = Crypt::randomStringHashed(55);
-    Drupal::state()->set('system.private_key', $key);
-  }
-  return $key;
+  return \Drupal::csrfToken()->getPrivateKey();
 }
 
 /**
  * Generates a token based on $value, the user session, and the private key.
  *
- * @param $value
+ * @param string $value
  *   An additional value to base the token on.
  *
  * @return string
@@ -3051,28 +3051,34 @@ function drupal_get_private_key() {
  *   'drupal_private_key' configuration variable.
  *
  * @see drupal_get_hash_salt()
+ * @see \Drupal\Core\Access\CsrfTokenManager
+ *
+ * @deprecated as of Drupal 8.0. Use the csrf_token service instead.
  */
 function drupal_get_token($value = '') {
-  return Crypt::hmacBase64($value, session_id() . drupal_get_private_key() . drupal_get_hash_salt());
+  return \Drupal::csrfToken()->get($value);
 }
 
 /**
  * Validates a token based on $value, the user session, and the private key.
  *
- * @param $token
+ * @param string $token
  *   The token to be validated.
- * @param $value
+ * @param string $value
  *   An additional value to base the token on.
- * @param $skip_anonymous
+ * @param bool $skip_anonymous
  *   Set to true to skip token validation for anonymous users.
  *
- * @return
+ * @return bool
  *   True for a valid token, false for an invalid token. When $skip_anonymous
  *   is true, the return value will always be true for anonymous users.
+ *
+ * @see \Drupal\Core\Access\CsrfTokenManager
+ *
+ * @deprecated as of Drupal 8.0. Use the csrf_token service instead.
  */
 function drupal_valid_token($token, $value = '', $skip_anonymous = FALSE) {
-  global $user;
-  return (($skip_anonymous && $user->id() == 0) || ($token == drupal_get_token($value)));
+  return \Drupal::csrfToken()->validate($token, $value, $skip_anonymous);
 }
 
 /**
diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php
index db2552b..d3b0210 100644
--- a/core/lib/Drupal.php
+++ b/core/lib/Drupal.php
@@ -391,4 +391,14 @@ public static function languageManager() {
     return static::$container->get('language_manager');
   }
 
+  /**
+   * Returns the CSRF token manager service.
+   *
+   * @return \Drupal\Core\Access\CsrfTokenManager
+   *   The CSRF token manager.
+   */
+  public static function csrfToken() {
+    return static::$container->get('csrf_token');
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Access/CsrfTokenManager.php b/core/lib/Drupal/Core/Access/CsrfTokenManager.php
new file mode 100644
index 0000000..5adf613
--- /dev/null
+++ b/core/lib/Drupal/Core/Access/CsrfTokenManager.php
@@ -0,0 +1,130 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Access\CsrfTokenManager.
+ */
+
+namespace Drupal\Core\Access;
+
+use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
+use Drupal\Component\Utility\Crypt;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Generates and validates CSRF tokens.
+ *
+ * @see \Drupal\Tests\Core\Access\CsrfTokenManagerTest
+ */
+class CsrfTokenManager {
+
+  /**
+   * The state service.
+   *
+   * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
+   */
+  protected $state;
+
+  /**
+   * The current request object.
+   *
+   * @var \Symfony\Component\HttpFoundation\Request
+   */
+  protected $request;
+
+  /**
+   * Constructs the token manager.
+   *
+   * @param \Drupal\Core\KeyValueStore\KeyValueStoreInterface $state
+   *   The state service.
+   */
+  function __construct(KeyValueStoreInterface $state) {
+    $this->state = $state;
+  }
+
+  /**
+   * Sets the $request property.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The HttpRequest object representing the current request.
+   */
+  public function setRequest(Request $request) {
+    $this->request = $request;
+  }
+
+  /**
+   * Gets the private key.
+   *
+   * @return string
+   *   The private key.
+   */
+  public function getPrivateKey() {
+    if (!$key = $this->state->get('system.private_key')) {
+      $key = $this->createPrivateKey();
+      $this->setPrivateKey($key);
+    }
+
+    return $key;
+  }
+
+  /**
+   * Sets the private key.
+   *
+   * @param string $key
+   *
+   * @return \Drupal\Core\Access\CsrfTokenManager
+   *   An instance of this class instance.
+   */
+  public function setPrivateKey($key) {
+    $this->state->set('system.private_key', $key);
+    return $this;
+  }
+
+  /**
+   * Creates a new private key.
+   *
+   * @return string
+   *   The private key.
+   */
+  protected function createPrivateKey() {
+    return Crypt::randomStringHashed(55);
+  }
+
+  /**
+   * Generates a token based on $value, the user session, and the private key.
+   *
+   * @param string $value
+   *   (optional) An additional value to base the token on.
+   *
+   * @return string
+   *   A 43-character URL-safe token for validation, based on the user session
+   *   ID, the hash salt provided by drupal_get_hash_salt(), and the
+   *   'drupal_private_key' configuration variable.
+   *
+   * @see drupal_get_hash_salt()
+   */
+  public function get($value = '') {
+    return Crypt::hmacBase64($value, session_id() . $this->getPrivateKey() . drupal_get_hash_salt());
+  }
+
+  /**
+   * Validates a token based on $value, the user session, and the private key.
+   *
+   * @param string $token
+   *   The token to be validated.
+   * @param string $value
+   *   (optional) An additional value to base the token on.
+   * @param bool $skip_anonymous
+   *   (optional) Set to TRUE to skip token validation for anonymous users.
+   *
+   * @return bool
+   *   TRUE for a valid token, FALSE for an invalid token. When $skip_anonymous
+   *   is TRUE, the return value will always be TRUE for anonymous users.
+   */
+  public function validate($token, $value = '', $skip_anonymous = FALSE) {
+    $user = $this->request->attributes->get('account');
+
+    return ($skip_anonymous && $user->id() == 0) || ($token == $this->get($value));
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Access/CsrfTokenManagerTest.php b/core/tests/Drupal/Tests/Core/Access/CsrfTokenManagerTest.php
new file mode 100644
index 0000000..506a63c
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Access/CsrfTokenManagerTest.php
@@ -0,0 +1,123 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Access\CsrfTokenManagerTest.
+ */
+
+namespace Drupal\Tests\Core\Access {
+
+use Drupal\Tests\UnitTestCase;
+use Drupal\Core\Access\CsrfTokenManager;
+use Drupal\Component\Uuid\Uuid;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Tests the CSRF token manager.
+ */
+class CsrfTokenManagerTest extends UnitTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'CsrfTokenManager test',
+      'description' => 'Tests the CsrfTokenManager class.',
+      'group' => 'Access'
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp() {
+    parent::setUp();
+    $uuid = new Uuid();
+    $this->key = $uuid->generate();
+
+    $this->state = $this->getMock('Drupal\Core\KeyValueStore\KeyValueStoreInterface');
+
+    $this->manager = new CsrfTokenManager($this->state);
+    $this->manager->setRequest(new Request());
+  }
+
+  /**
+   * Tests CsrfTokenManager::getPrivateKey().
+   */
+  public function testGetPrivateKey() {
+    $this->state->expects($this->once())
+      ->method('get')
+      ->with('system.private_key')
+      ->will($this->returnValue($this->key));
+
+   $this->assertEquals($this->key, $this->manager->getPrivateKey());
+  }
+
+  /**
+   * Tests CsrfTokenManager::setPrivateKey().
+   */
+  public function testSetPrivateKey() {
+    $random_name = $this->randomName();
+
+    $this->state->expects($this->once())
+      ->method('set')
+      ->with('system.private_key', $random_name)
+      ->will($this->returnValue(TRUE));
+
+    $this->assertInstanceOf('\Drupal\Core\Access\CsrfTokenManager', $this->manager->setPrivateKey($random_name));
+  }
+
+  /**
+   * Tests CsrfTokenManager::getToken().
+   *
+   * @depends testGetPrivateKey
+   */
+  public function testGet() {
+    $this->mockAllStateMethods();
+
+    $this->assertInternalType('string', $this->manager->get());
+    $this->assertNotSame($this->manager->get(), $this->manager->get($this->randomName()));
+  }
+
+  /**
+   * Tests CsrfTokenManager::validateToken().
+   *
+   * @depends testGet
+   */
+  public function testValidate() {
+    $this->mockAllStateMethods();
+
+    $token = $this->manager->get();
+    $this->assertTrue($this->manager->validate($token));
+    $this->assertFalse($this->manager->validate($token, 'foo'));
+
+    $token = $this->manager->get('bar');
+    $this->assertTrue($this->manager->validate($token, 'bar'));
+  }
+
+  /**
+   * Adds mocked get and set methods for the state mock object.
+   */
+  protected function mockAllStateMethods() {
+    $this->state->expects($this->any())
+      ->method('set')
+      ->with('system.private_key')
+      ->will($this->returnValue(TRUE));
+    $this->state->expects($this->any())
+      ->method('get')
+      ->with('system.private_key')
+      ->will($this->returnValue($this->key));
+  }
+
+}
+
+}
+
+/**
+ * @todo Remove this when https://drupal.org/node/2036259 is resolved.
+ */
+namespace {
+  if (!function_exists('drupal_get_hash_salt')) {
+    function drupal_get_hash_salt() {
+      return hash('sha256', 'test_hash_salt');
+    }
+  }
+}
