Email Confirmation Authentication for Website

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815

Email Confirmation Authentication Implementation for Websites

Email confirmation authentication is a scheme where the user enters an email address, receives a message with a link or code, and completes login via that link. It's a passwordless authentication variant with an explicit ownership verification step.

Differs from Magic Link in that email verification can be a separate step during traditional registration—confirming the email exists and is accessible.

Two Usage Scenarios

Scenario 1: Verification on Registration User registers with password → receives email → confirms email → gains access to features.

Scenario 2: Passwordless Login via Email User enters email → receives email with link → clicks it → authenticated. No password at all.

Email Verification on Registration (Laravel)

// Model implements MustVerifyEmail
class User extends Authenticatable implements MustVerifyEmail
{
    // ...
}
// routes/auth.php
Route::get('/email/verify/{id}/{hash}', [VerifyEmailController::class, '__invoke'])
    ->middleware(['auth', 'signed', 'throttle:6,1'])
    ->name('verification.verify');

Route::post('/email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
    ->middleware(['auth', 'throttle:6,1'])
    ->name('verification.send');

Custom email template:

class User extends Authenticatable implements MustVerifyEmail
{
    public function sendEmailVerificationNotification(): void
    {
        $this->notify(new CustomVerifyEmailNotification());
    }
}

Signed URL

Laravel generates a signed URL expiring in 60 minutes:

$url = URL::temporarySignedRoute(
    'verification.verify',
    now()->addMinutes(60),
    ['id' => $user->id, 'hash' => sha1($user->email)]
);

The signature is HMAC-SHA256 with APP_KEY. Attempts to forge or modify parameters return 403.

OTP Code Instead of Link

Some projects prefer a 6-digit code instead of a link—more convenient when opening email on a different device:

$code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);

Cache::put(
    "email_verification:{$user->id}",
    hash('sha256', $code),
    now()->addMinutes(10)
);
// Code verification
public function verify(Request $request): JsonResponse
{
    $stored = Cache::get("email_verification:{$user->id}");

    if (!$stored || !hash_equals($stored, hash('sha256', $request->code))) {
        return response()->json(['message' => 'Invalid or expired code'], 422);
    }

    $user->markEmailAsVerified();
    Cache::forget("email_verification:{$user->id}");

    return response()->json(['message' => 'Email confirmed']);
}

Resend and Spam Protection

// Cooldown between resend requests
RateLimiter::for('email-verification', function (Request $request) {
    return Limit::perMinutes(5, 1)->by($request->user()->id);
});

Frontend shows countdown until resend is possible—typically 60 seconds.

Expiration and Invalid Links

If user clicks an expired link—redirect to a page offering to request a new email. Don't show a generic 403 without explanation.

Email Change

Changing email doesn't happen immediately—confirmation is sent to the new address first. Only after confirmation is the email updated. This prevents account takeover via email change.

// pending_email in users table or separate email_changes table
$user->update(['pending_email' => $newEmail]);
// Send verification to $newEmail
// On confirmation: $user->update(['email' => $newEmail, 'pending_email' => null])

Work Timeline

Stage Time
Registration verification (standard) 1 day
Custom email templates 0.5 day
OTP code instead of link 1 day
Email change with confirmation 1 day
Tests + edge cases 1 day

Basic verification on registration—1–2 days. Full flow with email change and OTP—4–5 days.