Is this the correct way to implement a HMAC token system?
This looks good. 

I do almost exactly the same thing as a password reset mechanism. I am including it here in case it will help you with adding a timer to help prevent replay attacks.  

The user receives an email with a link to click to reset their password (the $oldpassword is the nonce because once the password is changed once, it is not valid anymore and the HMAC key is the old password salt (used by the php crypt function)).

$time = time();
$userid = $user-&gt;id;
$oldpassword = hash('sha256', $password_info['Password']);
$token = "t={$time}&amp;i={$userid}&amp;o={$oldpassword}";
$verification = hash_hmac('sha256', $token, $password_info['Salt']);

$newpasswordurl = Router::url('user_r')-&gt;uri(array(
    't' =&gt; $time,
    'i' =&gt; $userid,
    'o' =&gt; $oldpassword,
    'v' =&gt; $verification,
));


The validation is similar.

$userid = $input['i'];
$time = $input['t'];
$expire_time = date_create_from_format('U', $input['t'])-&gt;add(date_interval_create_from_date_string(self::$settings['ResetPassword']['LinkValidityTime']));
$oldpassword = $input['o'];
$hash = $input['v'];

$p_info = self::getPasswordParts($OldPassword);

$token = "t=$time&amp;i=$UserID&amp;o=$oldpassword";
$correct_hash = hash_hmac('sha256', $token, $p_info['Salt']);

if ( ($hash != $correct_hash) || ($oldpassword != hash('sha256', $p_info['Password'])) ) {
    throw new ChangePasswordException("That password link is invalid, has expired or has been used.");
}