When a user logs in, I want to redirect them to another page if they have a certain role.

In Drupal 7, I'd use drupal_goto() in an implementation of hook_user_login() to do the redirect, and hook_module_implements_alter() to make sure that my module is last in the list, so that everything else gets a chance to run.

In Drupal 8, drupal_goto() was removed and it seems that performing a redirect outside of a controller is not a supported use case.

On that page, gngn has the same problem, and manually generates a RedirectResponse and sends it.

The problem is that, as I see it, the send() doesn't terminate the request and the page will have two HTML documents: a 'redirecting to...' page, followed by whatever page would have been there in the first place. Which could be a security issue.

johnvb notes this, and inserts a call to exit() after the send().

But presumably something useful is being done in the $kernel->terminate() call in index.php, which is being bypassed by calling exit().

In Drupal 7, drupal_goto() called drupal_exit() to handle this problem. Drupal 8 has removed drupal_exit().

That page says that modules needing to interrupt the request flow should throw an HTTP exception, but there are no 'redirect' exceptions.

As the user login also does a redirect, another approach would be to alter the redirection URL, as suggested on the drupal_goto() change record link above.

However, that approach will result in my method being called on every single request, which for what I'm doing seems insanely wasteful.

So, how should I perform a redirect from within a form alter in Drupal 8?

use Drupal\Core\Form\FormStateInterface;

 * Implements hook_form_FORM_ID_alter().

function [MODULENAME]_form_user_login_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  // Alter login form and add own custom submit handler.
  $form['#submit'][] = '_[MODULENAME]_user_login_form_submit';

 * Custom submit handler for login form.
function _[MODULENAME]_user_login_form_submit($form, FormStateInterface $form_state) {
  // Set redirect to login form.

You have several ways to redirect user after login. As in the previous answers you can do it by implementing hook_form_FORM_ID_alter() and adding additional submit function, but you can still use hook_user_login function too:

To redirect to some route with parameters generating some url (using Symfony\Component\Validator\Constraints\Url class reference):

$form_state->setRedirectUrl(new Url('route_name', ['route' => 'parameters'])); 

To redirect to some route:

$form_state->setRedirect('route_name', ['route' => 'parameters']);

Also you can use Symfony\Component\HttpFoundation\RedirectResponse, for example if you want to redirect a user to some custom user page:

function your_module_user_login($account) {
    global $base_url;
    $redirect = new RedirectResponse($base_url .'/your-url/'.$account->uid->value);

  • Where would I get $form_state from if I'm using hook_user_login? Using RedirectResponse like this results in two responses being sent (the redirect masks it, but it's not good security practice) – Claw Dec 13 '16 at 22:23
  • Yes, i agree, RedirectResponse is not a good example in this context. It can be used in other redirect purposes not in form API. – Andrew Nim Dec 14 '16 at 10:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.