5

I am trying to implement a PHP persistent login solution to protect some admin pages on a website I'm working on, using this SO answer as the basis:

PHP login system: Remember Me (persistent cookie)

After Logging In

if ($login->success && $login->rememberMe) { // However you implement it
    $selector = base64_encode(openssl_random_pseudo_bytes(9));
    $authenticator = openssl_random_pseudo_bytes(33);

    setcookie(
        'remember',
         $selector.':'.base64_encode($authenticator),
         time() + 864000,
         '/',
         'yourdomain.com',
         true, // TLS-only
         true  // http-only
    );

    $database->exec(
        "INSERT INTO auth_tokens (selector, token, userid, expires) VALUES (?, ?, ?, ?)", 
        [
            $selector,
            hash('sha256', $authenticator),
            $login->userId,
            date('Y-m-d\TH:i:s', time() + 864000)
        ]
    );
}

Re-Authenticating On Page Load

if (empty($_SESSION['userid']) && !empty($_COOKIE['remember'])) {
    list($selector, $authenticator) = explode(':', $_COOKIE['remember']);

    $row = $database->selectRow(
        "SELECT * FROM auth_tokens WHERE selector = ?",
        [
            $selector
        ]
    );

    if (hash_equals($row['token'], hash('sha256', base64_decode($authenticator)))) {
        $_SESSION['userid'] = $row['userid'];
        // Then regenerate login token as above
    }
}

My question is that I don't understand what is meant by this section in the "Re-Authenticating On Page Load" section:

// Then regenerate login token as above

Which is the login token it's referring to - does that mean this bit:

$selector = base64_encode(openssl_random_pseudo_bytes(9));

Or this bit:

$authenticator = openssl_random_pseudo_bytes(33);

And once I have done that, do I have to:

  1. Add another row to the "auth_tokens" table
  2. Re-generate the cookie to include the new token value?

I've been trying various options for persistent logins all week, and this has almost got me there, but I'm stumbling at this last block.

Community
  • 1
  • 1
4532066
  • 2,042
  • 5
  • 21
  • 48

1 Answers1

2

When you login the first time, if you check the "remember me" box, two things will happen:

  1. Their current HTTP session will be updated with whatever information is needed to tie the session to an active user account.
  2. A cookie will be placed on the user's computer containing the long-term authentication token.

The token consists of selector:verifier as a concatenated string.

The next time your user comes to your website, if they don't have an active session, the cookie will be used to automatically log them in as the associated user. This token should then be discarded on both sides (browser and database) and a new one should be generated to take its place.

The end result is: To end users, it's like they're logged in forever (until they explicitly log out, which should invalidate the tokens).

Scott Arciszewski
  • 33,610
  • 16
  • 89
  • 206
  • 1
    Thanks for your answer, much appreciated. The thing I don't understand is how to discard that token in the scenario where I have got to the bit saying "// Then regenerate login token as above". Do I delete the row from "auth_tokens" for that token and then basically re-do the whole of the "After Logging In" section that's inside the if statement? Sorry for asking silly questions. Thanks – 4532066 Apr 22 '16 at 18:06
  • Yep. That's it. And set the new value in the user's cookie. – Scott Arciszewski Apr 22 '16 at 18:50