Currently Available: Need a skilled Software Developer for your next project?
Categories
Laravel

Limit User Registrations by IP Address in Laravel Jetstream

If you provide services to free users in your Laravel Jetstream application, you might want to prevent people from creating multiple accounts from the same IP address. Here's a straightforward way to implement this restriction.

Implementation

The cleanest way to add this restriction is by modifying the CreateNewUser action that Jetstream provides. This class handles the user registration process, making it the perfect place to add our IP-based validation.

1. Configuration

First, add a configuration value to config/auth.php:

'max_signups_per_ip' => env('MAX_SIGNUPS_PER_IP', 3),

And in your .env file:

MAX_SIGNUPS_PER_IP=3

2. Modifying CreateNewUser

In your app/Actions/Fortify/CreateNewUser.php, add the IP checking logic:

use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Config;

class CreateNewUser implements CreatesNewUsers
{
    protected function checkIpLimit(string $ip): bool
    {
        try {
            $redisKey = 'signups:' . $ip;
            $maxSignups = Config::get('auth.max_signups_per_ip', 3);
            $trackingPeriod = 86400; // 24 hours

            $currentCount = Redis::get($redisKey);

            if ($currentCount === null) {
                Redis::setex($redisKey, $trackingPeriod, 1);
                return true;
            }

            if (intval($currentCount) >= $maxSignups) {
                return false;
            }

            Redis::incr($redisKey);
            return true;
        } catch (\Exception $e) {
            \Log::error('Redis error in IP signup check', [
                'error' => $e->getMessage(),
                'ip' => $ip
            ]);
            return true; // Fail open if Redis is down
        }
    }

    public function create(array $input): User
    {
        Validator::make($input, [
            'name' => ['required', 'string', 'max:255'],
            'email' => [
                'required',
                'string',
                'email',
                'max:255',
                'unique:users',
                function ($attribute, $value, $fail) {
                    if (!$this->checkIpLimit(request()->ip())) {
                        $fail('Maximum number of accounts reached from this IP address.');
                    }
                },
            ],
            'password' => $this->passwordRules(),
            'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['accepted', 'required'] : '',
        ])->validate();

        // ... rest of the create method
    }
}

How It Works

The implementation uses Redis to track how many accounts have been created from each IP address:

  1. When a user tries to register, we check their IP address
  2. Redis keeps track of registration counts using keys that expire after 24 hours
  3. If an IP has reached the limit, registration is blocked with a validation error
  4. The counter automatically resets after 24 hours

Error Handling

The implementation includes error handling for Redis failures. If Redis is unavailable, the system will:

  1. Log the error
  2. Allow the registration to proceed
  3. Not block any registrations until Redis is available again

Considerations

When implementing IP-based restrictions, keep in mind:

  • Users behind shared IPs (offices, universities) might hit limits
  • VPN users can bypass restrictions by changing their IP
  • The 24-hour period is rolling (not calendar-based)
  • Redis must be configured in your Laravel application
What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Subscribe to my newsletter

Get new posts when I publish them.

I respect your privacy. Unsubscribe at any time.

Leave a Reply

Your email address will not be published. Required fields are marked *