I am writing my own 403 page, and would like to redirect the user to the login page if the user is not logged in. I use this code in a page callback, but when I am viewing an unauthorized page (say /user/1) as anonymous user, I got infinite redirect to /user/1.

function MODULE_membercheck() {
    global $user;
    if (!$user->uid) {
        //drupal_goto('user/login', array('query' => array('destination' => 'member/check')));
        drupal_goto('user/login'); //these two lines won't work 
    // other stuff.


It is quite easy to reproduce the problem. Just create a module and add a menu (member/check), and redirect anonymous user to login page in the page callback function. Then set the default 403 page to this menu entry, and try to open an unauthorized page.

  • Anonymous user is uid 0, try to check for that specific id instead of ! having one.
    – tdd
    Oct 6, 2015 at 9:58
  • If you try an other un-othorized page like admin/content, do you have also an infinite redirect to admin/content ?
    – pbonnefoi
    Oct 6, 2015 at 9:58
  • @pbonnefoi Yes, I have tried that. Will drupal add destination to the url query when direct to 403 page? I don't see that at the url.
    – leetom
    Oct 6, 2015 at 10:03
  • @tdd Sure, but that is not the problem here.
    – leetom
    Oct 6, 2015 at 10:04
  • Try to replace 'user/login' by 'user'
    – pbonnefoi
    Oct 6, 2015 at 10:11

3 Answers 3


Where is MODULE_membercheck() getting called from? It would seem that it's getting called on user/login page requests which makes these pages redirect to themselves, hence the infinite loop.

You can either modify the calling of the function to ensure it doesn't get called on the login page or add a check in your function to make sure the current path is NOT user/login before doing the redirect, something like this:

function MODULE_membercheck(){
  global $user;
  if (!$user->uid && current_path() != '/user/login') {
    drupal_goto('user/login', array('query' => array('destination' => 'member/check')));
  // other stuff.
  • I'd probably check for current_path() instead of request_uri(), as the latter could contain arguments. Oct 6, 2015 at 20:52
  • I don't think this is the problem. The callback function is not called on user/login page. If it is getting called, then the browser will be redirect to user/login again and again instead of user/1 (the original url).
    – leetom
    Oct 7, 2015 at 17:48
  • Hi @ciss, good catch! I've updated the code as per your comment. Oct 8, 2015 at 14:39
  • @leetom, just to clarify, does that mean that you've added the path condition and it's still doing the infinite loop? Oct 8, 2015 at 14:40
  • @PaulQuerol Yes, still the same. It looks like drupal is adding destination when it shows the 403 page, but I don't see any parameters related.
    – leetom
    Oct 9, 2015 at 5:59

Below are 2 options to implement what you're looking for, provided using a contributed module for this is acceptable (if not you may want to use it as a temporary work around).

Option 1: Use the CustomError module

The CustomError module allows the site admin to create custom error pages for HTTP status codes 403 (access denied) and 404 (not found), without creating nodes for each of them. Some more details about its features (from its project page):

  • Configurable page title and descriptions.
  • There are no author and date/time headers as with normal nodes.
  • Any HTML formatted text can be be put in the page body.
  • The error pages are themable.
  • Users who are not logged in and try to access an area that requires login will be redirected to the page they were trying to access after they login.
  • Allows custom redirects for 404s.

You'll probably be interested mostly in the part about "Users who are not logged in and try to access an area that requires login will be redirected to the page they were trying to access after they login.".

Option 2: Use the Rules module

Assume the path of the "Default 403" page is set to no_access (via admin). Then create a rule using the Rules module, with as Event something like "After visiting node no_access". So that the entire rule would look something like so:

  • Events: After visiting node no_access
  • Conditions:

    1. User has role(s) - Parameter: User: [site:current-user], Roles: anonymous user
    2. NOT Text comparison - Parameter: Text: [site:current-page:url], Matching text: user/login
  • Actions: Page redirect - Parameter: URL: user/login

  • This sounds like what I need, but I am still wondering why my module won't work.
    – leetom
    Oct 9, 2015 at 6:00

I was also running into redirection loop with drupal_goto() (was trying to send anonymous users to login page) with no obvious reason. Then I replaced drupal_goto() with php's header() redirection and it worked well. Not sure what was the problem with drupal_goto() but other one saved the day. It's worth trying.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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