A visual guide to WordPress user login hooks

In this article, we are going to discuss the WordPress hooks that are triggered during the user login process. WordPress calls many different actions and filters throughout its sign in process.

To customize the default WordPress login functionality, you will need to understand which hooks are called and when they are called in the code execution. That’s why we have created a detailed graphic that will help you understand the sequence of these hooks and how everything fits together.

WordPress hooks is one of the most powerful features available to developers. WordPress fires various hooks throughout the request cycle, allowing us to customize almost every aspect of it.

WordPress hooks are functions that allow you to modify or add code to the default WordPress functionality. They can be used to add new functionality to WordPress or to change the way that existing functionality works.

There are two types of hooks in WordPress – actions and filters. Actions allow injecting custom functionality at different points of the code execution. Filters enable modifying the values of the variables at the different stages of the request cycle.

This article is a continuation of the A visual guide to WordPress user registration hooks article, where we’ve dived into the WordPress user registration hooks.

WordPress user login actions and filters

In this section we are going to discuss the login hooks that are fired by using the default WordPress login form, assuming a successful login. These apply for both the login form that is located at /wp-login.php  and for any login forms that are generated by using the wp_login_form()  function. Please note that if you are using a third-party plugin for your login functionality, the hooks fired might be different. Additionally, WordPress allows plugins to overwrite some of the login functions, which could also change the default hook cycle. So, in this article we are going to focus on the default WordPress login hooks, assuming no modifications to the default functionality.

The following graphic illustrates all the main hooks that are fired during the login process:

WordPress user login hooks visualized

As you can see the login action consists of two HTTP requests:

  • The first request is the one that performs all the login-related actions, such as validation, authentication, and setting up the authentication cookies. Once the login is successful and the authentication cookies are set, WordPress would return a 302 Redirect response, to redirect to a selected page.
  • The second request is loading the redirected page. If you are using the default WordPress login form, the redirected page will be the admin dashboard, located at /wp-admin . Otherwise, if you are using the wp_login_form() function, you will be able to set a redirect page in its arguments. Or you can alternatively use the login_redirect  filter that we are going to discuss later in this article.

Now let’s go through each of these login actions and filters. We’ll start with the login request hooks.

Login request hooks

determine_current_user filter and set_current_user action

These two hooks are not related with the login process, however, it’s important to visualize them, so you can understand where they stand in this process. The determine_current_user  filter allows you to modify the current user that is set. The set_current_user action is triggered after the current user has been set.

Here it is important to mention that these two hooks are triggered before the login authentication. Therefore in this request, if you attempt to get the current user ID by using the wp_get_current_user() function, the user ID will be set to 0. Also, the is_user_logged_in() function here will return false.

function my_custom_user_action(){
    $user = wp_get_current_user();
    $user->ID; // 0
    is_user_logged_in(); // false
add_action('set_current_user', 'my_custom_user_action');

wp_authenticate action

The wp_authenticate  action is triggered just before the user is authenticated. This action passes the username/email and the password as arguments by reference, which means that they can be modified from a callback.

authenticate filter

If you need to perform custom validation/authentication rules, one of the hooks that you can use is the authenticate filter.

The default WordPress authentication is hooked to this filter. It is not called a function within the login process, but it is executed as a callback of the authenticate filter. Therefore if you are planning to use the authenticate filter, it’s important to understand how WordPress uses this filter. Use this hook with caution, as incorrect usage might mess up the default WordPress login functionality.

This is how WordPress hooks its login authentication functionality to this filter:

add_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
add_filter( 'authenticate', 'wp_authenticate_email_password', 20, 3 );
add_filter( 'authenticate', 'wp_authenticate_spam_check',  99 );
add_filter( 'authenticate', 'wp_authenticate_cookie', 30, 3);

The wp_authenticate_username_password and wp_authenticate_email_password callbacks include the main WordPress authentication functionality. They attempt to authenticate the user by username and email correspondingly. These two callbacks are hooked with a priority of 20. After that, the wp_authenticate_cookie callback is called with a priority of 30. If the username/password verification fails to authenticate the user, this function will check for the presence of an authentication cookie.

The authenticate filter passes three arguments – user object, username, and password. If you hook to this filter with a priority smaller than 20, the user object will be set to null.

function my_authenticate($user, $username, $password){
    // $user here will be null
    return $user;
add_filter('authenticate', 'my_authenticate', 10, 3);

However, if you use a priority greater than 20, your code will be executed after the WordPress authentication. If the authentication is successful, then the user object will be set with the corresponding WP_User instance.

function my_authenticate($user, $username, $password){
    // $user here will be an instance of WP_User class, given a successful authentication
    return $user;
add_filter('authenticate', 'my_authenticate', 25, 3);

If the last executed callback returns a WP_User instance, the authentication will be successful. However, if it returns null as a result, the authentication process will be terminated and the login will fail. To learn more about this hook, head over to the WordPress authenticate filter documentation.

The priority of your custom authentication rule will depend on your desired outcome. If you need to add an additional authentication method, you would need to use a priority smaller than 20. This is because the WordPress authentication callbacks will be executed only when the passed user object is set to null. By doing this, your callback can return a user object and bypass the default WordPress authentication callbacks.

If you want to make your authentication stronger and stop people from being able to log in depending on certain rules, you would need to use a priority that is higher than 30. For example, if you want to stop someone from being able to login when they sign in from a different device, you could use a callback with a higher priority and return null .


wp_authenticate_user filter

As you can see in the graphic above, the wp_authenticate_user  filter is fired during the WordPress authentication process. This filter is called just after WordPress has performed the validation to check if a user exists with the given username or email. If a user with this username or email doesn’t exist, this hook will not be fired. It is also important to mention that this hook is fired before password validation. Therefore, at the point of calling this hook, it is still not determined whether the authentication has been successful or not.

This is another filter that you can use to apply custom validations. If your callback returns a WP_Error  instance, the login process will be aborted. You can read more about this filter in the wp_authenticate_user guide.

auth_cookie filter

The auth_cookie filter is called after successful authentication. You can use it to filter the authentication cookies. WordPress sets two authentication cookies – “auth” and “logged in”, and therefore the filter is called separately for each of them. The “auth” cookie is mainly used for authentication in the admin area. The “logged in” cookie, on the other hand, is used throughout the site to identify the logged in user. You can read more on the WordPress Cookies codex page.

The authentication cookies are unique strings, that consist of the user’s username, cookie expiration date, session token, and a hash. It’s generally not recommended to modify this string unless you really know what you are doing. Also, if you need to modify it, consider using more specific filters. For example, if you need to change the expiration date, you could use the auth_cookie_expiration  filter instead.

Just after this filter, the set_auth_cookie and set_logged_in_cookie actions are also called, passing the cookie details as parameters. These actions are called just before the cookies are sent to the client.

send_auth_cookies filter

This filter is called immediately before the authentication and logged in cookies are set. If for some reason you need to prevent the cookies from being sent, you can use this filter. The filter sends a boolean true  as an argument. If your callback returns false, the authentication cookies will not be set. Use this filter with caution, as improper usage can lead to disabling the login functionality on your site.

wp_login action

The wp_login action is called after a successful login. Therefore, if you need to perform a certain action only after a successful login, this is the hook that you can use. One important thing to mention is that if the send_auth_cookies filter is used to prevent sending the authentication cookies, the wp_login would still be triggered.

The wp_login hook passes the username and the user object as parameters to the callback. For more information and examples on how to hook to this action, visit the WordPress codex page. This is how it is invoked in WordPress:

do_action( 'wp_login', $user->user_login, $user );

login_redirect filter

The login_redirect filter allows you to change the page that the user is redirected to after a successful login. This is the final hook that is executed before redirecting the user after a successful login.

Login redirect request hooks

Now let’s take a look at the user-related hooks in the second request that performs the redirection. As you can see from the graphic above, WordPress calls the determine_current_user  filter and the set_current_user action, just like on the previous request. These two hooks are called on every request. This time, however, if you hook to the set_current_user action, you will have access to the current user object.

So, the set_current_user action in the redirection request is the first action where you can access the current user object after a successful sign in. By hooking to this action or any other actions/filters fired after it, you can now use functions like wp_get_current_user()  to get the logged in the user object.

function my_custom_user_action(){
    $user = wp_get_current_user();
    $user->ID; // 123 (current user ID)
    is_user_logged_in(); // true
add_action('set_current_user', 'my_custom_user_action');


This article explores some of the most important hooks that WordPress fires during a successful login. We already know that the login process for WordPress is quite involved and consists of various different elements. The two different requests that WordPress makes can sometimes be confusing, especially when you access the current user object. Therefore, if you need to modify the login functionality, it’s essential to understand how everything fits together, so you can choose the right hooks to accomplish your task.

We hope you’ve found this article helpful, and see you again next time!