Proper way to pass credentials in a custom login form to avoid “headers already sent”

I’m working on a custom login page plugin. I’m trying to figure out how to log the user in without creating “headers already sent” errors.

I was calling wp_signon directly after the user clicked “login,” but quickly found that this approach yields “headers already sent” errors. I’ve switched to using hooks:

private function attemptLogin() {
    add_action( 'after_setup_theme', array( $this->Cms, 'authenticateUser' ), 10, 2 );
    do_action( 'after_setup_theme', $_POST['username'], $_POST['password'] );

But, as you’ve probably guessed, this yields the same errors since I’m still, in essence, executing the login immediately.

How can I leave the hook to run on its own schedule to avoid errors, while still making the user’s credentials available to it?

I’ve searched both Google and this site for the answer to no avail. The closest to an answer I’ve found is this, but I’m still unsure how to implement the advice while still passing the user’s credentials.

Solutions Collecting From Web of "Proper way to pass credentials in a custom login form to avoid “headers already sent”"

Upon successful login wp_signon() sets a cookie in the http response header. Hence it has to be called before any HTML output is sent to the browser. Otherwise the “headers already sent” error will occur.

After a successfull login you should redirect your user. Otherwise the login information will not present when the page HTML is rendered.

A very sketchy but working code:

// process login requests each time wordpress renders a page. 
function my_custom_login_process() {
    // check if login credentials are present in the current http request
    if ( isset( $_POST['user_login'] ) && isset( $_POST['user_password'] ) ) {
        // try login
        $user = wp_signon( $_POST );

        if ( is_wp_error($user) ) // didn't work. Tell the user.
        else // worked! Get him somewhere.
            wp_redirect( get_bloginfo('url') );

Additionally you should protect your login form with a nonce, and add a nonce verification to the function above. The easiest way to do this is by using wp_nonce_field() in the login form.

Nonces explained

[EDIT]: A Nonce is a unique token, that gets registered along with a form. It is mainly used to make sure that a form has been generated by the Webserver, before any data is accepted for further processing. All forms in the admin area are using nonces (or at least should do).

During the login process it will provide basic protection against brute force attacks. (This means flooding your WordPress with blank POST requests containing arbitrary username / password combinations.)

(BTW: It seems like you have a little misconception on hooks. You really should not register (do_action()) and call a hook (do_action()) with arbitrary function arguments. Other plugins might also have registered their functions. This article looks like a pretty good starting point for a deeper understanding.)