Crypt::hmacBase64() versus CsrfTokenGenerator::get() and CsrfTokenGenerator::validate() In a module I am writing, I need to add a hidden field in the registration form, similarly to what the Honeypot module does.

$form['honeypot_time'] = [
  '#type' =&gt; 'hidden',
  '#title' =&gt; t('Timestamp'),
  '#default_value' =&gt; mymodule_get_signed_timestamp(time()),
  '#element_validate' =&gt; ['mymodule_signed_timestamp_validate'],
  '#cache' =&gt; [
    'max-age' =&gt; 0,
  ],
];


mymodule_get_signed_timestamp() concatenates the timestamp with a value used to avoid the timestamp is arbitrary changed. It could be computed in one of two ways:


Using Crypt::hmacBase64()
Using the csrf_token service, which by default provides CsrfTokenGenerator::get() and CsrfTokenGenerator::validate()


The choose is then between one of the following snippets.

use \Drupal\Component\Utility;

$token = Crypt::hmacBase64($value, \Drupal::service('private_key')-&gt;get());




use \Drupal\Core\Access;

$token = \Drupal::csrfToken()-&gt;get($value);


The difference is apparently just that the csrf_token service's methods use, as part of the key passed to Crypt::hmacBase64(), also the session's data and the hash salt set in the settings.php file.

Considering that, in most of the cases, I would be altering a form submitted from anonymous users who tries to register an account (but I cannot exclude I could be adding that form element to forms submitted from registered users), should I use the first method or the second one?
I made a quick test using the following code.

use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Drupal\Core\Site\Settings;
use Drupal\Core\Access\CsrfToken;
use Drupal\Component\Utility\Crypt;

$autoloader = require_once 'autoload.php';

/**
 * Global flag to identify update.php and authorize.php runs.
 *
 * Identifies update.php and authorize.php runs, avoiding unwanted operations
 * such as css/js preprocessing and translation, and solves some theming issues.
 * The flag is checked in other places in Drupal code (not just authorize.php).
 */
const MAINTENANCE_MODE = 'update';

try {
  $request = Request::createFromGlobals();
  $kernel = DrupalKernel::createFromRequest($request, $autoloader, 'prod');
  $kernel-&gt;prepareLegacyRequest($request);
}
catch (HttpExceptionInterface $e) {
  $response = new Response('', $e-&gt;getStatusCode());
  $response-&gt;prepare($request)-&gt;send();
  exit;
}

\Drupal::moduleHandler()-&gt;addModule('system', 'core/modules/system');
\Drupal::moduleHandler()-&gt;addModule('user', 'core/modules/user');
\Drupal::moduleHandler()-&gt;load('system');
\Drupal::moduleHandler()-&gt;load('user');

drupal_maintenance_theme();

$csrf_token = \Drupal::csrfToken();

$content[] = [
  '#markup' =&gt; t('First method: %token.&lt;br /&gt;', ['%token' =&gt; Crypt::hmacBase64(123456, \Drupal::service('private_key')-&gt;get())]),
  '#cache' =&gt; ['max-age' =&gt; 0],
];
$content[] = [
  '#markup' =&gt; t('Second method: %token.&lt;br /&gt;', ['%token' =&gt; $csrf_token-&gt;get(123456)]),
  '#cache' =&gt; ['max-age' =&gt; 0],
];

$renderer = \Drupal::service('bare_html_page_renderer');
$response = $renderer-&gt;renderBarePage($content, 'Test results', 'maintenance_page', array(
  '#show_messages' =&gt; FALSE,
));

$response-&gt;setStatusCode(400);
$response-&gt;send();


I then opened three different Firefox windows pointing them at the test script I wrote. This is what I got:

First window


  First method: r3xavuZbwgsk1RJTPm-zOs3kUSeSY4-BDnj-UCwgyr0.
  Second method: OndzLnnASZLsuzABJltD_HwK8dr48fEW_hdWG9Lu02I.


Second window


  First method: r3xavuZbwgsk1RJTPm-zOs3kUSeSY4-BDnj-UCwgyr0.
  Second method: J6oHkKdXeL9RUKHX4B1Sn418Yh8XD0tJbRrs459BI7A.


Third window


  First method: r3xavuZbwgsk1RJTPm-zOs3kUSeSY4-BDnj-UCwgyr0.
  Second method: TYvxZiF7xS6hD2nn8pfHu0GR9OPw0X8xT1HfVDNWkXc.


With the second method, different users are going to get different values, even in the case the input value is the same.
I would say that using the csrf_token service is preferable, in my case.