14

I would like to redirect users after they log in. Is it possible to use hook_user_login() to make the redirection? How do I add the parameter for the redirection?

18 Answers 18

20

You need to alter the login form and add a submit handler which will take care of the redirection. You cannot use $form_state->setRedirectUrl() directly in the form alter, since it will be overwritten by UserForm::submitForm().

/**
 * Implements hook_form_FORM_ID_alter().
 */
function mymodule_form_user_login_form_alter(&$form, FormStateInterface $form_state) {
  $form['#submit'][] = 'mymodule_user_login_submit';
}

/**
 * Form submission handler for user_login_form().
 *
 * Redirects the user to the dashboard after logging in.
 */
function mymodule_user_login_submit(&$form, FormStateInterface $form_state) {
  $url = Url::fromRoute('mymodule.dashboard');

  // Check if a destination was set, probably on an exception controller.
  // @see \Drupal\user\Form\UserLoginForm::submitForm()
  $request = \Drupal::service('request_stack')->getCurrentRequest();
  if (!$request->request->has('destination')) {
    $form_state->setRedirectUrl($url);
  }
  else {
    $request->query->set('destination', $request->request->get('destination'));
  }
}
| improve this answer | |
  • 4
    As described by @kiamlaluno, one can also use $form_state->setRedirect('mymodule.dashboard); – Filipe Miguel Fonseca Jan 6 '17 at 6:57
  • 3
    Please explain users who follow this answer what mymodule.dashboard should/would do. How to change that to <front>, just for an example. Since user dashboard is the default redirect after login, this example here is useless. The new user do not know which parts to alter and how for his redirect. – nilsun Oct 21 '17 at 10:53
  • 1
    To redirect to the front page, you can use the example above but change the line that generates the $url object to $url = Url::fromUri('internal:/'); – oknate Nov 9 '17 at 21:41
  • 1
    I don't understand what's happening in the else here? Maintaining an existing redirect? – user1359 Oct 12 '18 at 15:14
  • 1
    you have to use use Drupal\Core\Url; to make it working correctly – Jignesh Rawal Oct 24 '18 at 9:13
16

Redirecting users after they login on a Drupal 8 site is not different from how it was done on Drupal 7, except the code needs to be adapted for Drupal 8.

In particular:

  • hook_user_login() is not used to redirect users after they login, simply for the fact that redirecting users in that hook would stop other hook_user_login() implementations from being invoked.
  • The correct way to redirect users is adding a form submission handler to the login form that uses code similar to the following one.

    $form_state->setRedirect('user.page');
    

    Notice that user.page is the routing name for the Drupal path where you want the user to be redirected.
    If you have an instance of the Drupal\Core\Url class, you could also use the following code.

    $form_state->setRedirectUrl($url);
    

    Keep in mind that the first method is preferable when you are redirecting users to a page in the same site they logged in; the second method is normally used to redirect users using an external URL.

| improve this answer | |
11

you can use hook_user_login and try to redirect to yourpath

function yourmodule_user_login($account) {
  // We want to redirect user on login.
  $response = new RedirectResponse("yourpath");
  $response->send();
  return;
}

Also you can use Rules module, but there is NOT stable version for Drupal 8 yet.

| improve this answer | |
  • A good elegant solution, worked for me in Drupal 8.1. – Alexei Rayu May 2 '16 at 9:55
  • 3
    I was getting ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION errors in certain circumstances with the above - I suggest replacing return; with exit;, to ensure the redirect - which sets headers - is the last thing to be executed. – user34185 Jul 14 '16 at 14:19
  • 2
    hook_user_login() is called before the submit handlers so this would prevent them from being called. Yogesh's answer below is a better way of doing this. – imclean Oct 1 '18 at 1:29
10

Bit late to the party but as per https://www.drupal.org/node/2068293#comment-11712455 you can set the destination in hook_user_login() to redirect at the end of the login processing.

i.e.

/**
 * Implements hook_user_login().
 */
function mymodule_user_login(\Drupal\user\UserInterface $account) {
  // Ignore password reset.
  $route_name = \Drupal::routeMatch()->getRouteName();
  if ($route_name !== 'user.reset.login') {
    // Do not interfere if a destination was already set.
    $current_request = \Drupal::service('request_stack')->getCurrentRequest();
    if (!$current_request->query->get('destination')) {
      // Default login destination to the dashboard.
      $current_request->query->set(
        'destination',
        \Drupal\Core\Url::fromRoute('mymodule.dashboard')->toString()
      );
    }
  }
}

Using FormState::setRedirect() as per the other answers will probably cover most people's use cases and is potentially the 'right' answer, however using the destination query param with hook_user_login means that any form submit* that logs in the user will redirect but without interference or prior knowledge of any other part of the form/request.

i.e. it will still work with a custom login form and using destination does not stop any other hooks (it is implemented by \Drupal\Core\EventSubscriber\RedirectResponseSubscriber at the end of response processing).

*Any form submit that invokes hook_user_login (user_login_finalize()) and does not manually call FormState::setResponse().

| improve this answer | |
  • 1
    This has the advantage of working if authentication happens from something other than a login form. But does this interfere with other hook_user_login implementations from other modules? – Jonathan Jul 29 '17 at 18:34
  • 1
    @Jonathan No, it only sets the destination and doesn't do an early request->send() or anything (i.e. like d7 drupal_goto), it will allow all other hooks, form callbacks etc to run like normal before it is acted upon. This is just how the standard drupal login redirect does it. – Sut3kh Jul 30 '17 at 21:39
  • 1
    Please explain users who follow this answer what mymodule.dashboard should/would do. How to change that to <front>, just for an example. Since user dashboard is the default redirect after login, this example here is useless. The new user do not know which parts to alter and how for his redirect. – nilsun Oct 21 '17 at 10:54
  • 3
    @nilsun mymodule.dashboard is the route name and can be replaced with any route name (i.e. \Drupal\Core\Url::fromRoute('<front>')->toString() or \Drupal\Core\Url::fromRoute('entity.node.canonical', ['node' => 123])->toString()). For more information see drupal.org/docs/8/api/routing-system/routing-system-overview and api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Url.php/… – Sut3kh Dec 21 '17 at 22:16
  • 2
    This breaks password reset so I'm down-voting the answer. (Creating a form submission handler for user_login_form as suggested in another answer works.) – hansfn Nov 5 '18 at 13:51
7

You can simply do it by using Rules

React on: After user has logged in

  • Add action: Redirect >> then use a parameter or type your url.
| improve this answer | |
  • 3
    The main caveat on this is that Rules is still in pre-release ALPHA for Drupal 8 so take care if you need stability on your website – Philippe Gilbert Aug 30 '18 at 18:08
  • 1
    Rules messes up the login system when the site has redirect to a page after user logs in. Beware – InspiredCoder Mar 1 '19 at 10:52
6

You can also alter the user login form and add your own custom submit handler to set $form_state redirect, instead of directly redirecting user to your custom URL using hook_user_login.

<?php
/**
 * Implements hook_form_alter().
 */
function [MODULENAME]_form_alter(&$form, \Drupal\Core\Form\FormStateInterface\FormStateInterface $form_state, $form_id) {
  switch ($form_id) {
    // Alter login form and add own custom submit handler.
    case 'user_login_form':
      $form['#submit'][] = '_[MODULENAME]_user_login_form_submit';
      break;
  }
}

/**
 * Custom submit handler for login form.
 */
function _[MODULENAME]_user_login_form_submit($form, FormStateInterface $form_state) {
  // Set redirect to login form.
  $form_state->setRedirect('YOUR.MENU-ROUTER.NAME');
}

Adding it in $form_state redirect will make sure that the other submit handlers/login hooks get called.

Like Drupal7 we can't set $form_state['redirect'] directly, because $form_state is now class object. Checkout FormState::setRedirect() for further details.

| improve this answer | |
6

In D8, you can use user default page module for this purpose.

This module allows you to customize the destination that a user is redirected to after logging in or logged out. You can customize by roles or individual users.

| improve this answer | |
  • 1
    Works but it doesn't take in consideration password reset links, when the user uses the one time link to set their password it redirects them to the page you set in this module and not the user account. – Sorin Aug 24 '17 at 14:58
  • 1
    This module still breaks password reset so I'm down-voting the answer. See drupal.org/project/user_default_page/issues/2991916 (Creating a form submission handler for user_login_form as suggested in another answer works.) – hansfn Nov 5 '18 at 13:52
4

There is a simple module to do this which is compatible with Drupal 8. It is called User Default Page.

The module allows you to customize the destination that a user is redirected to after logging in or logged out. You can customize by roles or individual users. And customize configurable drupal messages for this actions.

| improve this answer | |
3

hook_user_login() doesn't work for redirection, it's used if you want to do something with the user when he logs in. Fx core suggests users to set the local timezone if it's not set.

Instead you need to use hook_form_alter on all of the login forms and add a custom submit handler which sets the redirect on the form state object.

| improve this answer | |
2

I am displaying the login form in my own controller. That way it's possible to manipulate the form (and so redirect the user after login) without the non-OO hooks:

$fb = $this->formBuilder();
$rc['top'] = ['#markup' => '<p>Willkommen im Kundenbereich von proreos. 
    Bitte melden Sie sich hier mit Ihrem
    Benutzernamen oder Ihrer Email Addresse an.</p>'];
$form = $fb->getForm("Drupal\user\Form\UserLoginForm");

$ug = $this->getUrlGenerator();
$redir = $ug->generateFromRoute('proreos.home', [], 
         ['query' => $this->getDestinationArray(), 'external' => FALSE]);
$form['#action'] = $redir;

$rc['login'] = $form;

return $rc;

Change the 'proreos.home' route to whatever destination you need.

Regards

Rainer

| improve this answer | |
2

Simply add destination parameter to login url.
Example: http://example.com/user/login?destination=/my-page

If you doing it for 403 ( Access Denied ) pages use following module:
https://www.drupal.org/project/redirect_403_to_login_page

| improve this answer | |
2

I use the following snippet quite a lot so I thought I'd share it. You can add different redirects depending on which role the user has.

use Symfony\Component\HttpFoundation\RedirectResponse;

/**
 * Redirect on login.
 */
function MYMODULE_user_login($account) {
  $roles = $account->getRoles();
  if(in_array('webmaster', $roles)) {
    $response = new RedirectResponse('/admin/content');
    $response->send();
  }
}
| improve this answer | |
1

Use any of these modules:

https://www.drupal.org/project/login_redirect

OR

https://www.drupal.org/project/login_destination

Cheers

| improve this answer | |
  • 4
    D8 version is not available. Question tag for D8 not for D7. – DRUPWAY Aug 19 '16 at 6:58
1

You can use logintoboggan module for redirection. It has other configuratrions which may be useful if you want other functionlaities like login using usernames.

| improve this answer | |
  • 2
    Good answer for D7, but this question is tagged D8, and there's no Drupal 8 version of Logintoboggan yet. – Kelley Curry Jan 17 '19 at 14:43
1

https://www.drupal.org/project/redirect

  1. Install the above module
  2. Add custom url path as the destination parameter in the url
  3. So, configure the above module to redirect from

    /user/login to /user/login?destination='CUSTOM_NODE_PATH'

    • Wanted to use r4032login module to allow authenticated users access the concerned page, when they copy/paste the url or use an hyperlink from word/excel for example.
    • Other 'login redirect' modules would override this functionality and would only allow users to land on a configured single page even when the destination parameters are included in the url
| improve this answer | |
1

Another option specifically for this issue is a simple Drupal 8 contributed module: Redirect After Login. The module can be found here:

https://www.drupal.org/project/redirect_after_login

As the description shows, it is a simple, focused module that is covered by the Drupal security advisory policy.

| improve this answer | |
1

/**
 * hook_user_login Redirect to English language whenever admin login
 **/
function modulename_user_login($account) {
  // We want to redirect user on login.
  $response = new Symfony\Component\HttpFoundation\RedirectResponse("/en/admin/config");
  $response->send();
  return;
}
| improve this answer | |
0

​I was working on a way to get around the other things that depend on hook_user_login because many other options are breaking in the newer versions of 8. Some other re-direct modules do a lot of leg-work that is either no longer relevant and/or just out-right hogging resources. I put together this simple logic into a custom module for handling the login processes:

function hook_user_login( UserInterface $account ) {
  // Doing checks to see if the login is from an HTML origin or not.
  // Could be from RESTful request to logins
  $request = \Drupal::request();
  if ($request->getRequestFormat() !== 'html') {
    // default
    return;
  }

  // Get the destination to see where the login request is going.
  // This is useful to check for interactions from user creations.
  $destination = $request->query->get('destination');

  // Check the destination. If the destination will result in a re-direct 
  // to your homepage (here statically defined, but could be programmatic)
  // then you can force re-direct to a different page. This is the URL defined
  // in config > system > basic site settings.
  if ($destination && $destination === '/whatever-homepage-uri-is') {
    // Regular login, send to alternate welcome page
    $response = new RedirectResponse('/welcome');
    $response->send();
    exit;
  }

  // default
  return;
}

I have been using this successfully with Drupal 8.8.3 and it does not break my REST login requests from another module I built, re-directs correctly for new account creations, and then re-directs to a different page on a regular site login.

| improve this answer | |

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.