Score:0

Clean logout from REST service

lc flag

Considering that none of the usual suggestions really work...

The standard user/logout provided by Drupal has CSRF issues, as numerous questions describe, it shows a "'csrf_token' URL query argument is invalid" even if the appropriate token is provided (going deep into the core shows that it can't successfully validate the logout token provided, hence the error).

The obvious solution then is to create our own REST service to log out, especially if using REST for other purposes in a module, too, all it takes is just one more call. The service can simply call user_logout() to have core perform it for us.

However, at least in current Drupal 10.1, while this results in a spurious "Warning: session_destroy(): Trying to destroy uninitialized session" warning. Core's SessionManager actually calls PHP's session_destroy() with a comment describing that it does it on purpose instead of calling the corresponding Symfony function. When checking the sessions table in the database, these sessions actually stay there, so the user isn't really logged out at all.

Logging out in a browser the usual way doesn't leave a warning like that so this is clearly some problem with the programmatic approach. But no matter how I check the source, I can't see why...

For reference, the REST resource I try (slightly different, this one makes the relevant calls from user_logout() directly but there's no difference by either calling that or doing this way):

class UserResource extends ResourceBase {
  protected AccountProxyInterface $currentUser;
  protected SessionManager $sessionManager;

  public function __construct(array $config, $module_id, $module_definition, array $serializer_formats, LoggerInterface $logger, AccountProxyInterface $current_user, SessionManager $session_manager) {
    parent::__construct($config, $module_id, $module_definition, $serializer_formats, $logger);
    $this->currentUser = $current_user;
    $this->sessionManager = $session_manager;
  }

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): UserResource {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->getParameter('serializer.formats'),
      $container->get('logger.factory')->get('user'),
      $container->get('current_user'),
      $container->get('session_manager'),
    );
  }

  /**
   * Logs out a user.
   * Replacement for the stock one that gives AccessDeniedHttpException: 'csrf_token' URL query argument is invalid.
   * Based on user.module::user_logout()
   */
  public function get(): ResourceResponse {
    // user_logout();
    $this->sessionManager->destroy();
    $this->logger->info('Session closed for %name.', ['%name' => $this->currentUser->getAccountName()]);
    return new ResourceResponse(NULL, 204);
  }

  public function permissions(): array {
    return [];
  }
}
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.