First round of refinements on the login system...

There's a lot more to do on the to-do list
This commit is contained in:
Dan Baker 2026-02-22 20:02:09 +00:00
parent 82ed2e3ce2
commit 1b241aeddb
7 changed files with 390 additions and 219 deletions

View file

@ -2,6 +2,7 @@
namespace App\Services;
use App\DTOs\MagicTokenResult;
use App\Models\MagicLoginToken;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
@ -15,9 +16,9 @@ class MagicLinkAuthService
*
* @throws ValidationException
*/
public function sendMagicLink(string $email, ?string $ip, ?string $ua): MagicLoginToken
public function sendMagicLink(string $email, ?string $ip, ?string $ua): MagicTokenResult
{
$key = 'magic-link:' . hash('sha256', strtolower(trim($email)));
$key = 'magic-link:' . User::hashEmail($email);
if (RateLimiter::tooManyAttempts($key, 5)) {
$seconds = RateLimiter::availableIn($key);
@ -31,10 +32,8 @@ class MagicLinkAuthService
RateLimiter::hit($key, 3600);
$user = User::findByEmail($email);
if (!$user) {
$user = User::create([
if (!User::findByEmail($email)) {
User::create([
'email_hash' => User::hashEmail($email),
]);
}
@ -48,7 +47,7 @@ class MagicLinkAuthService
public function verifyMagicLink(string $token): bool
{
$magicToken = MagicLoginToken::valid()
->where('plain_token', $token)
->where('token_hash', hash('sha256', $token))
->first();
if (!$magicToken) {
@ -63,6 +62,11 @@ class MagicLinkAuthService
$magicToken->markAsUsed();
if (is_null($user->email_verified_at)) {
$user->email_verified_at = now();
$user->save();
}
Auth::login($user, true);
return true;
@ -70,6 +74,8 @@ class MagicLinkAuthService
/**
* Verify a magic code and log the user in.
*
* @throws ValidationException
*/
public function verifyCode(string $email, string $code): bool
{
@ -77,7 +83,13 @@ class MagicLinkAuthService
$key = 'magic-code:' . $emailHash;
if (RateLimiter::tooManyAttempts($key, 5)) {
return false;
$seconds = RateLimiter::availableIn($key);
throw ValidationException::withMessages([
'code' => [
"Too many attempts. Please try again in {$seconds} seconds.",
],
]);
}
$magicToken = MagicLoginToken::valid()
@ -100,6 +112,11 @@ class MagicLinkAuthService
RateLimiter::clear($key);
if (is_null($user->email_verified_at)) {
$user->email_verified_at = now();
$user->save();
}
Auth::login($user, true);
return true;