User Registration Implementation 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

User Registration Implementation on Website

Registration is the first user interaction with the authentication system. Here the user table structure, email verification logic, password policy, and bot protection are established. Most security issues that appear later stem from here.

User Table Structure

Minimal schema covering most scenarios:

CREATE TABLE users (
    id          BIGSERIAL PRIMARY KEY,
    email       VARCHAR(255) NOT NULL UNIQUE,
    password    VARCHAR(255),               -- NULL for OAuth registration
    name        VARCHAR(255),
    email_verified_at TIMESTAMP,
    status      VARCHAR(20) NOT NULL DEFAULT 'pending',
    remember_token VARCHAR(100),
    created_at  TIMESTAMP DEFAULT NOW(),
    updated_at  TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_status ON users(status);

Field password is nullable because user can register via social provider without password. status takes values pending (email unverified), active, banned, deleted (soft delete).

Password Hashing

bcrypt with cost factor 12 is the current standard. In PHP: password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]). In Node.js: bcrypt.hash(password, 12). Argon2id is preferable for security, but bcrypt is sufficient and universally supported.

Never store plaintext passwords, don't log form data, don't pass passwords in URL parameters. This is obvious but violated regularly.

Backend Validation

Frontend validation — for UX. Backend validation — for security. Both are mandatory, they don't replace each other.

// Laravel FormRequest
class RegisterRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'email'    => ['required', 'email:rfc,dns', 'max:255', 'unique:users,email'],
            'password' => ['required', 'min:8', 'max:72', 'confirmed', Password::defaults()],
            'name'     => ['required', 'string', 'max:255'],
        ];
    }
}

email:rfc,dns checks format by RFC and MX record existence. Filters out non-existent domains before sending email. max:72 for password is bcrypt limitation (truncates strings longer than 72 bytes).

For password policy in Laravel: Password::min(8)->letters()->mixedCase()->numbers(). Don't overdo requirements — NIST SP 800-63B recommends length over complexity.

Email Verification

Without verification, anyone can register with someone else's email, receive notifications to wrong inbox, pollute database with garbage. Verification is mandatory everywhere email is used as identifier.

Verification token is a signed link with TTL:

// Generate link
$verifyUrl = URL::temporarySignedRoute(
    'verification.verify',
    now()->addHours(24),
    ['id' => $user->id, 'hash' => sha1($user->email)]
);

// Handle verification
public function verify(Request $request): RedirectResponse
{
    if (! hash_equals(sha1($request->user()->email), $request->hash)) {
        abort(403);
    }

    $request->user()->markEmailAsVerified();

    return redirect('/dashboard')->with('status', 'email-verified');
}

Temporary signed link is better than storing token in DB — no separate table needed, link is self-contained and expires automatically.

Bot Protection and Abuse

Rate limiting: max 5 registration attempts per IP per 10 minutes. In Laravel:

RateLimiter::for('register', function (Request $request) {
    return Limit::perMinutes(10, 5)->by($request->ip());
});

Honeypot: hidden form field that bots fill, humans don't:

<input type="text" name="website" style="display:none" tabindex="-1" autocomplete="off">

On backend: if website is not empty — silently reject.

CAPTCHA: reCAPTCHA v3 (score-based, no user interaction) or hCaptcha. Enable on anomalous activity, not by default — CAPTCHA reduces conversion.

Social Registration

OAuth registration via Google, GitHub, VK — users prefer it, no password to invent. Processing logic:

public function handleOAuthCallback(string $provider): RedirectResponse
{
    $socialUser = Socialite::driver($provider)->user();

    $user = User::where('email', $socialUser->getEmail())->first();

    if ($user) {
        // Already exists — link provider
        $user->oauthProviders()->updateOrCreate(
            ['provider' => $provider],
            ['provider_id' => $socialUser->getId()]
        );
    } else {
        // New user
        $user = User::create([
            'email'             => $socialUser->getEmail(),
            'name'              => $socialUser->getName(),
            'email_verified_at' => now(), // email already verified by OAuth provider
            'status'            => 'active',
        ]);
    }

    Auth::login($user);
    return redirect('/dashboard');
}

Important: if OAuth email matches existing account with password — don't create duplicate, link provider to existing account.

Post-Registration Flow

After successful registration, typical scenario:

  1. Send welcome email with verification link
  2. Create user initial data (profile, default settings)
  3. Redirect to dashboard or "check email" page
  4. Optionally: onboarding wizard on first login

Email sent via queue, not synchronously — otherwise SMTP delay blocks user response.

Typical time for basic registration with email verification: 1–2 working days. With OAuth providers — add 1 day per provider.