44

I am looking for the API that will let me login a user by passing it the username and password. Does anyone have experience with this?

To clarify, I am trying to make an AJAX login box that appears as a popup on the home page, and do not refresh the page in case of wrong credentials, but only if the log in is correct. So here is what i have done so far:

Update

I now load the login form on my homepage, then on submission I launch an AJAX request that sends credential to this script:

function user_login_submit_try() {
  global $user;  
    
  $uid = user_authenticate($_POST['name'],$_POST['pass']);    
  $arr = array ('name'=>$_POST['name'],'pass'=>$_POST['pass']);
  if ($uid){
    $user = user_load($uid);
    user_login_finalize($arr);
  }

  echo drupal_json_encode($uid); 
  exit;
}; 
   

So far it works, but my worries are (as mentioned by googletorp) security issues; it seems that none of the API I used in this script sanitized the data in anyway.

Would anyone see a better way to do so?

2

7 Answers 7

34

This might help someone:

function mymodule_user_login_credentials($username, $password)
{
    if(user_authenticate($username, $password))
    {
      $user_obj = user_load_by_name($username);
      $form_state = array();
      $form_state['uid'] = $user_obj->uid;      
      user_login_submit(array(), $form_state);
      return true;
    }
    else
    {
        return false;
    }
}

A better version based on the comment:

function mymodule_user_login_credentials($username, $password)
{
    if($uid = user_authenticate($username, $password))
    {
      user_login_submit(array(), array('uid' => $uid));
      return true;
    }
    else
    {
        return false;
    }
}
4
  • 3
    user_authenticate already returns the $uid so no need to load the user object ;)
    – FLY
    Aug 22, 2013 at 12:07
  • 7
    The second code block will not work; user_login_submit's 2nd arg is passed by ref; passing it the output of array() will fail.
    – Shawn Conn
    Apr 8, 2015 at 6:11
  • How would this answer be used to auto-login a user after they have been created using a registration form? I would like to do that, but the password is a hash when provided via the account object as parameter in hook_user_insert but the above functions in the answer want the password as the original plain text. I guess I'll need to try hook_form_alter instead... Jan 25, 2018 at 15:33
  • For folks looking for automatic login directly after the new user has been created (e.g. via a user sign-up registration form e.g. 'user/register'), see this solution: drupal.stackexchange.com/a/254905/1082 Feb 1, 2018 at 11:46
20

There is not a simple API function for that.

You can do what Drupal does:

  1. Test the password by querying the database see:

user_login_name_validate()
user_login_authenticate_validate()
user_login_final_validate()

  1. Overwrite the global $user.

    global $user;
    $user = user_load($uid);
    
  2. Handle sessions

user_login_finalize($form_state);

For step two and 3 see user_login_submit()

All these functions are based on being called from a form. The normal flow is that the validate handlers test the users input and returns the uid of the user if validation passes. The submit handler then handles the actual login of the user and calling user hook.

6
  • thanks googletorp, i ll try that out, although this let me wonder on how this functions work together.. How does one know that i did invoke the precedent ?
    – silkAdmin
    Jun 25, 2011 at 9:16
  • oh and if i do not have the From_state variable availlable but just username and password, can i rebuild it like : $form_state['value']['name'] = $_POST['name'] and so on..
    – silkAdmin
    Jun 25, 2011 at 9:18
  • @silk You should always use the Drupal FAPI which gives you the $form_state variable. There are a lot of nice security checks that you would otherwise loose and possible open your site for attacks. When it comes to logging in a user, you don't want to loose that security.
    – googletorp
    Jun 25, 2011 at 9:48
  • Please check my updated question, i'd really like to know if my inputs get cleaned up.. Thanks
    – silkAdmin
    Jun 25, 2011 at 10:12
  • Sorry it seems that the edit didn't work the first time, now it's updated.
    – silkAdmin
    Jun 27, 2011 at 13:26
7

If you need to get the user object for the user account for which you know username and password, then you can use the following code:

function mymodule_get_user(name, $password) {
  $account = FALSE;

  if ($uid = user_authenticate($name, $password)) {
    $account = user_load($uid);
  }

  return $account;
}

$account will be FALSE if the user object cannot be found or loaded.

You should use this code when, for example, your module gets the username and password as input from a user, it verifies if they are correct, and then it does something with the user object.
If you are writing a module that needs to impersonate a user to write a comment, or doing something else that needs to result as done by a user, which is what the Project issue tracking module does when closing an issue report that has been in the fixed status for two weeks (in that case, it adds the comment "Automatically closed -- issue fixed for 2 weeks with no activity" which results written by the "System Message" user), then you don't need username and password. You just load the user object for which you know the user ID.

As far as I know, there aren't any security issues with the code I reported.
You could want to limit the number of failed logins; or to temporary block the IP which tries to log in without success, or tries different logins in short time.

1
  • thank you kiamlaluno , it kind of what i did, but i am now worrying about security issues, please check out my updated question
    – silkAdmin
    Jun 27, 2011 at 13:28
3

This code really works

//login
$uid = user_authenticate($username, $password);
global $user;
$user = user_load($uid);    
//login finalize
watchdog('remote_user', 'Session opened for %name.', array('%name' => $user->name));
$user->login = REQUEST_TIME;
db_update('users')
  ->fields(array('login' => $user->login))
  ->condition('uid', $user->uid)
  ->execute();
drupal_session_regenerate();
1
  • It doesn't invoke hook_user_login, see user_login_finalize() function.
    – skorzh
    Sep 7, 2016 at 7:16
2

Cleaned up answer from the above. Checking user and password is an additional feature. Also, the fake form_state needs to be a variable to be passed by reference to the function or it throws an error.

Hence we have:

function mymodule_log_in_by_uid($uid) {
    $faux_form_state = array('uid' => $uid);
    user_login_submit(array(), $faux_form_state);
}
1

The user will receive the session and will also be logged on to other pages:

function custom_log_in_by_uid($uid) {
    $form_state = array('uid' => $uid);
    user_login_submit(array(), $form_state);
}
0

Sometimes we need quick login from URL or Forgot admin password. Just implement below two functions to login as user 1 in Drupal.

function mymodule_menu(){
    $items['login/as/admin'] = array(
        'title' => 'Login as admin account',
        'page callback' => 'mymodule_login_as_admin',
        'access callback' => TRUE,
        'type' => MENU_CALLBACK,
    );
    return $items;
}
function mymodule_login_as_admin(){
    global $user;
    $user = user_load(1);
    return "Global user set as admin. Please refresh page ";
}

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.