Login a MODX User with the API

There are times when developing we need to create a new MODX User or search for an existing user and perform an action that typically results in logging that user into a MODX context. In this thought experiment, we'll be exploring a number of different ways to create users, search for users and log them in all via the API.

Creating a user

To get started we'll create a user, the code below is a fairly typical user creation flow in MODX:

PHP
<?php

/**
 * Search for an existing user based on an Email address
 */

$request = $modx->sanitize($_REQUEST);
$email = trim($request['email']);

// If using formit you could do 
# $email = $hook->getValue('email');

// Get the user object
$User = $modx->getObject('modUser', [
    'username' => $email
]);
// Check that we have a User object 
if (!is_object($User)) {
    try {
        // No User object, we can safely assume that there is 
        // no user registered with this Username 
        // so we can go ahead and create one
        $User = $modx->newObject('modUser');
        // Generate a password for this new user 
        $pwd = $User->generatePassword();
        // Set some details
        $User->fromArray([
            'username' => $request['email'],
            'password' => $pwd,
            'active' => 1, // Important! Set them to active 
        ]);

        $userProfile = $modx->newObject('modUserProfile');
        $userProfile->fromArray([
            'internalKey' => $User->get('id'),
            'blockeduntil' => 0,
            'blocked' => 0,
            'blockedafter' => 0,
            'fullname'  => $request['fullname'],
            'email'     => $request['email'],
            'extended'  => [
                'first_login' => 1
            ]
        ]);
        $User->addOne($userProfile);

        if ($User->save() === false) {
            throw new RuntimeException("Unable to create new user", 500);
        }
        // Add this user to the right user group 
        // Params -> groupID, roleID, rank 
        // check out https://docs.modx.com/current/en/building-sites/client-proofing/security/user-groups
        $User->joinGroup(3, 1);

        return $User->get('id');
    } catch (RuntimeException $e) {

        return $e->getMessage();
    }
}

Searching for users

To search for users we can use some of the following techniques:

PHP
// Search for user with username (typically an eamil address)
try {
    $query = $modx->newQuery('modUser');
    $query->where([
        'username' => $email,
    ]);
    $User = $modx->getObject('modUser', $query);
    if (!is_object($User)) {
        throw new RuntimeException(sprintf("No user found with username %s", $email), 404);
    }

    return $User->get('id');
} catch (RuntimeException $e) {

    return $e->getMessage();
}
PHP
// Search for user by email and username
try {
    $query = $modx->newQuery('modUserProfile');
    $query->where([
        'email' => $email,
    ]);
    $User = $modx->getObject('modUserProfile', $query);
    if (!is_object($User)) {
        throw new RuntimeException(sprintf("No user found with email address %s", $email), 404);
    }
    // internal key is the ID of the modUser object
    return $User->get('internalKey');
} catch (RuntimeException $e) {

    return $e->getMessage();
}
PHP
// Adapted from the Login Extra 

// Only accept login via email address if it exists only once!
$count = $modx->getCount('modUserProfile', array(
    'email' => $email,
));
if ($count > 1) {
    $criteria = array ('modUser.username' => $email);
} else {
    $criteria = array(
        array('modUser.username' => $email),
        array('OR:Profile.email:=' => $email)
    );
}

$User = $modx->getObjectGraph('modUser', '{"Profile":{},"UserSettings":{}}', $criteria);

Logging in 

Above is a really simple flow for creating a user if one doesn't exist, however, this article is about logging that user into a Modx Context. In this next section, we'll explore the different ways to achieve this goal.

Login processor 

The first method is to run the MODX Login processor which takes a username, password, and context to try and log the user into. This method is best suited for forms that ask for a username and password.

PHP
<?php

$data = array(
    'username' => $request['email'],
    'password' => $pwd, // The password generated above or pass in the password provided ie. $request['password']
    'rememberme' => 1,
    'login_context' => 'web', // context to log the user into
);
$response = $modx->runProcessor('/security/login', $data);
if ($response->isError()) {
    throw new RuntimeException($response->getMessage(), 500);
}

Add a context session

The second method is ideal for forms that don't request passwords but can be sure that the email address provided is linked to this existing user. This is best used with payment or donation forms where you want to reduce the signup friction.

PHP
<?php

$contextName = 'web'; // the name of the context you'd like to log the user into
$User->addSessionContext($contextName);