WordPress reset password returns invalid key

I’m currently trying to build a custom reset password form, which seems to work fine up until it needs to validate the key for the user:

//Redirect away from default wordpress to reset password
function redirect_to_reset_password() {
    if ( 'GET' == $_SERVER['REQUEST_METHOD'] ) {
        // Verify key / login combo
        $user = check_password_reset_key( $_REQUEST['key'], $_REQUEST['login'] );
        if ( ! $user || is_wp_error( $user ) ) {
            if ( $user && $user->get_error_code() === 'expired_key' ) {
                wp_redirect( home_url( '/login?login=expiredkey/' ) );
            } else {
                wp_redirect( home_url( '/login?login=invalidkey/' ) );
            }
            exit;
        }

        $redirect_url = home_url( '/reset-password/' );
        $redirect_url = add_query_arg( 'login', esc_attr( $_REQUEST['login'] ), $redirect_url );
        $redirect_url = add_query_arg( 'key', esc_attr( $_REQUEST['key'] ), $redirect_url );

        wp_redirect( $redirect_url );
        exit;
    }
}
add_action('login_form_rp', 'redirect_to_reset_password');
add_action('login_form_resetpass', 'redirect_to_reset_password');

//Make new password
function do_password_reset() {
    if ( 'POST' == $_SERVER['REQUEST_METHOD'] ) {
        $rp_key = $_REQUEST['rp_key'];
        $rp_login = $_REQUEST['rp_login'];
        $user = check_password_reset_key( $rp_key, $rp_login );

        if ( ! $user || is_wp_error( $user ) ) {
            if ( $user && $user->get_error_code() === 'expired_key' ) {
                wp_redirect( home_url( '/login?login=expiredkey/' ) );
            } else {
                wp_redirect( home_url( '/login?login=invalidkey/' ) );
            }
            exit;
        }

        if ( isset( $_POST['pass1'] ) ) {
            if ( $_POST['pass1'] != $_POST['pass2'] ) {
                // Passwords don't match
                $redirect_url = home_url( '/reset-password/' );

                $redirect_url = add_query_arg( 'key', $rp_key, $redirect_url );
                $redirect_url = add_query_arg( 'login', $rp_login, $redirect_url );
                $redirect_url = add_query_arg( 'error', 'password_reset_mismatch', $redirect_url );

                wp_redirect( $redirect_url );
                exit;
            }

            if ( empty( $_POST['pass1'] ) ) {
                // Password is empty
                $redirect_url = home_url( '/reset-password/' );

                $redirect_url = add_query_arg( 'key', $rp_key, $redirect_url );
                $redirect_url = add_query_arg( 'login', $rp_login, $redirect_url );
                $redirect_url = add_query_arg( 'error', 'password_reset_empty', $redirect_url );

                wp_redirect( $redirect_url );
                exit;
            }

            // Parameter checks OK, reset password
            reset_password( $user, $_POST['pass1'] );
            wp_redirect( home_url( '/login?password=changed/' ) );
        } else {
            echo "Invalid request.";
        }

        exit;
    }
}
add_action( 'login_form_rp', 'do_password_reset' );
add_action( 'login_form_resetpass', 'do_password_reset' );

I’ve been snooping around trying to figure out what the cause of the issue can be, and I’ve found that the key under user_activation_key is not the same as the one I get in my URL when trying to reset my password. E.g:

DB: 1553346836:$P$BYEbftAGRfnhlBTeuNL4ylhsxRyhS3/

URL: key=dx1GjoJnaD6Dytc5zpNq

I assume this is just wordpress’ way of encrypting the key so it shouldn’t cause this issue, but it is the only inconsistency I’ve been able to find.

EDIT: If I try and check what value $user is set to, I get an undefined index error regarding $_REQUEST['rp_key'] and $_REQUEST['rp_login']. I then tried to var_dump $_REQUEST which gave me the following: array(2) { ["login"]=> string(20) "[email protected]" ["key"]=> string(20) "nWrRCsRD4OvaROeMFErV" }. Following this I changed $_REQUEST[‘rp_key’] to $_REQUEST[‘key’] and the same for login, but I still get the same undefined index error. But the value is in the $_REQUEST array, why can’t it find it?

Could the fact that I’m using check_password_reset_key twice have an effect on the key being set to invalid?

EDIT2:
Running the code through a environment running https resulted in a “Bad Request” return.

2 Answers
2

I had the same issue with this, I assume you’re working from this guide – https://code.tutsplus.com/tutorials/build-a-custom-wordpress-user-flow-part-3-password-reset–cms-23811

Have a look at the actual reset password form where it shows pass1 and pass2. The hidden fields values are automatically set to $attribute['key'] and $attribute['login'].

Changing this to $_REQUEST['key'] and $_REQUEST['login'] should solve the issue.

Hope this helps.

Leave a Comment