OO Auth lib - On the right track?
Regarding try/catch: this depends on whether your user class can handle errors or not.


An exception you can't handle is for example if the SQL-statement has a syntax error or the SQL-server being down. You can't do anything about it programatically during runtime except for displaying a nice error message to the user. In that case I wouldn't surround the DB-code with try/catch but implement a global try/catch which does just display a nice error message to the user and log the errors for you, the developer.
But if you have an exception because for example your username-field is UNIQUEand someone tries to insert an username which already exists you could resolve that problem automatically by just adding a number to the username and retry the insert (okay it's a dumb example, but I hope the point comes across). The pseudocode for this dumb example could be like:

$statement = $db-&gt;prepare("INSERT INTO user (username, ....) values (?, ...)");
$tryInsert = true;
$tries = 0;
while($tryInsert) {
    $insertName = $username;
    if($tries &gt; 0) {
        $insertName .= $tries;
    }
    try {
        $statement-&gt;execute(array($insertName, ...));
        $tryInsert = false; // it worked, stop trying
    } catch(PDOException $e) {
        if($e-&gt;code() == "23000") {
            // 23000 means unique constraint violation, probably 
            // duplicate username
            ++$tries;
        } else {
            // we can't handle the exception, therefore we just re-throw it
            throw $e;
        }
    }
}



I think in your code are no exceptions which you could handle. If an exception occurs it is most probably due to some issue with the SQL-server or the SQL-statement is wrong. In that case it doesn't make sense to wrap any of your code in try/catch. But you should add some kind of global exception handler which displays a nice error message (like: oops something went wrong, the developers have been informed).
In login change the last two lines to:

if (($row = $this-&gt;STH-&gt;fetch()) !== false)
    return $row;


The problem with PDOStatement::recordCount() is, that it's not portable for SELECT queries and the above code does the same thing as your code.
Then in create_account, you use PDO::setAttribute to change the PDO error mode of the supplied PDO-instance. Change that so that this is called when the PDO is initialized and not deep down in some mapper-class.
Your activate method could be rewritten to just execute one query:

public function activate($key) {
    $this-&gt;STH = $this-&gt;DBH-&gt;prepare("UPDATE users SET activated = 1, activation_key = null WHERE activation_key = ?"); 
    $this-&gt;STH-&gt;execute(array($key));

    // rowCount is set to the number of rows affected by UPDATE
    return $this-&gt;STH-&gt;rowCount() &gt; 0;
}

Optional: This could be simplified:

if (isset($_SESSION['userid']) &amp;&amp; isset($_SESSION['hash'])) {


To that:

if (isset($_SESSION['userid'], $_SESSION['hash'])) {

Optional: Consider using phpass for hashing your passwords. It's definitely more secure that just sha1 with some salt thrown in and the class is simple to use. If you're doing this you would have to rework your login method a bit  (meaning the password verification must be done in PHP when using phpass).
If you like to change your check_*-methods you could do something like that:

protected function check_record($field, $value) {
    $this-&gt;STH = $this-&gt;DBH-&gt;prepare("SELECT COUNT(*) FROM users WHERE {$field} = ?");
    $this-&gt;STH-&gt;execute(array($value));

    $count = $this-&gt;STH-&gt;fetchColumn();

    if($count !== false) {
        return (int)$count &gt; 0;
    }

    return null;
}

public function check_username($username) {
    return $this-&gt;check_record("username", $username);
}

public function check_email($username) {
    return $this-&gt;check_record("email", $username);
}