Rate limiting is critical for protecting app or website resources from excessive or improper use. Whether a result of malicious human intervention, bot-based attacks, or an overlooked vulnerability, resource misuse can interfere with legitimate access to your application and introduce severe vulnerabilities.

This article explores how to add rate limiting to an API in a Laravel application.

Throttle Your API Traffic in Laravel

Rate limiting is a mechanism designed to mitigate the exploitation of your application’s resources. While it has many uses, it is particularly useful for public APIs in large, scalable systems. It ensures that all legitimate users retain fair access to system resources.

Rate limiting is also crucial for security, cost control, and overall system stability. It can help prevent request-based attacks, such as distributed denial-of-service (DDoS) attacks. This attack relies on sending repeated requests to overwhelm and disrupt access to an application or website server.

There are several methods for implementing rate limiting. You can use variables that characterize the requester to determine who can access your application and how frequently. Some common variables include:

  • IP Address — Implementing rate limits based on IP addresses enables you to restrict the number of requests per address. This method is especially beneficial in circumstances where users can access an application without providing credentials.
  • API Key — Limiting access via API keys entails providing the requester with pre-generated API keys and establishing rate limits on a per-key basis. With this approach, you can also apply different access levels to the generated API keys.
  • Client ID — You can also pre-generate a Client ID that a user can embed in the header or body of API requests. This method lets you set per-ID access levels to ensure no client can monopolize system resources.

Laravel Middleware

Middleware provides a convenient mechanism for inspecting and filtering HTTP requests entering an application. Essentially, it’s a layer of code between the application and its underlying infrastructure to enable communication among its resources.

How To Implement Rate Limits

This tutorial uses an existing mini library API on the Laravel 10 framework to demonstrate using Laravel Throttle. The sample starting project contains the basic create, read, update, and delete (CRUD) implementations needed to manage books in a collection and two extra routes to demonstrate some rate-limiting concepts.

Prerequisites

The tutorial assumes you are familiar with the basics of API development in Laravel. Ensure that you have the following:

You also use MyKinsta to set up and deploy this API. You can follow along with the provided project template and preview the final result from the complete source code.

Laravel Application Set Up

  1. To begin, clone the project template.
  2. Then, create a .env file in the project’s root directory and copy the contents of .env.example into it.
  3. Next, complete the setup using the following commands to install the application dependencies and generate the app key.
composer install
php artisan key:generate

If this command does not automatically add the app key to your .env file, run php artisan key:generate --show, copy the generated key, and paste it into your .env file as the value for APP_KEY.

  1. Once the dependencies installation and app key generation are complete, start the application using the following command:
php artisan serve

This command starts the application and makes it accessible via the browser at https://127.0.0.1:8000.

  1. Visit the URL to confirm that the Laravel welcome page populates:

The Laravel welcome page displays its logo at the top-center.
The Laravel welcome screen

Database Configurations

Let’s configure and set up the application database in MyKinsta.

  1. Navigate to your MyKinsta account dashboard and click the Add service button:

The upper segment of the MyKinsta Dashboard tab features a top toolbar.
MyKinsta dashboard with several services configured.

  1. On the Add service list, click Database and configure the parameters to start your database instance:

Kinsta's
MyKinsta database configuration.

This tutorial uses MariaDB, but you can choose any of the Laravel-supported database options that Kinsta provides.

  1. Once you’ve entered your database details, click the Continue button to finalize the process.

Databases provisioned on Kinsta have internal and external connection parameters. You should use internal connection parameters for applications hosted within the same Kinsta account and external parameters for external connections. Therefore, use Kinsta’s external database credentials for your application.

  1. Copy and update the app database’s .env credentials with the external credentials shown in the screenshot below:

The Kinsta dashboard displays the "Basic details" section of the newly created "library-records" database.All information matches that entered in the previous database setup image.
MyKinsta database configuration details.

DB_CONNECTION=mysql
DB_HOST=your_host_name
DB_PORT=your_port
DB_DATABASE=your_database_info
DB_USERNAME=your_username
DB_PASSWORD=your_password
  1. After filling in the database credentials, test the connection by applying database migration using the command below:
php artisan migrate

If everything functions properly, you should see a response similar to that shown below.

The terminal output displays the "php artisan migrate" Bash command and its output.Immediately below the command, an "INFO" label states "Running migrations."Below this are the four migrations and their statuses, listed as follows:2014_10_12_000000_create_users_table...812ms DONE.2014_10_12_100000_create_password_reset_tokens_table...882ms DONE.2019_08_19_000000_create_failed_jobs_table...942ms DONE.2019_12_14_000001_create_personal_access_tokens_table...1,250ms DONE.Below, the cursor sits on an empty command line to allow additional input.
Successful database migration on a terminal.

  1. Next, use the following command to list the application routes and see the routes already implemented.
php artisan route:list

You should now see the available API endpoints:

The terminal displays the "php artisan route:
Application’s route list on the terminal.

  1. Start the application and confirm that everything still works fine. You can test these endpoints via the terminal using a tool like Postman or CURL.

How To Rate Limit in a Laravel Application

Several rate-limiting techniques are available for Laravel applications. You can block a set of IP addresses or enforce duration-based request limits based on a user’s IP address or user_id. Next, you apply each of these methods.

  1. Install the Laravel Throttle package using the following command:
composer require "graham-campbell/throttle:^10.0"
  1. You can also make additional changes to the Laravel Throttle configurations by publishing the vendor configurations file:
php artisan vendor:publish --provider="GrahamCampbell\Throttle\ThrottleServiceProvider"

How To Block IP Addresses

One rate-limiting technique allows you to block requests from a specified set of IP addresses.

  1. To begin, create the necessary middleware:
php artisan make:middleware RestrictMiddleware
  1. Next, open the created app/Http/Middleware/RestrictMiddleware.php middleware file and replace the code in the handle function with the snippet below. Ensure you add use App; to the list of imports at the top of the file.
$restrictedIps = ['127.0.0.1', '102.129.158.0'];
if(in_array($request->ip(), $restrictedIps)){
  App::abort(403, 'Request forbidden');
}
return $next($request);
  1. In the app/Http/Kernel.php file, create an alias for this middleware app by updating the middlewareAliases array as follows:
    protected $middlewareAliases = [
    . . .
    'custom.restrict' => \App\Http\Middleware\RestrictMiddleware::class,
    ];
    1. Then, apply this middleware to the /restricted-route in the routes/api.php file as follows and test:
    Route::middleware(['custom.restrict'])->group(function () {
      Route::get('/restricted-route', [BookController::class, 'getBooks']);
    });

    When working correctly, this middleware blocks all requests from the IPs in the $restrictedIps array: 127.0.0.1 and 102.129.158.0. Requests from these IPs return a 403 Forbidden response, as shown below:

    The Postman app returns a "403 Request Forbidden" response to a GET request to the URL
    A 403 Forbidden response for the /restricted-route GET endpoint on Postman

    How To Throttle Requests by IP Address

    Next, you rate limit requests using the user’s IP address.

    1. Apply the Throttle middleware to the /book endpoint’s GET and PATCH routes in routes/api.php:
    Route::middleware(['throttle:minute'])->group(function () {
      Route::get('/book', [BookController::class, 'getBooks']);
    });
    
    Route::middleware(['throttle:5,1'])->group(function () {
      Route::patch('/book', [BookController::class, 'updateBook']);
    });
    1. You must also update the configureRateLimiting function in the app/Providers/RouteServiceProvider file with the middleware you added to the above routes.
    … 
    RateLimiter::for('minute', function (Request $request) {
      return Limit::perMinute(5)->by($request->ip());
    });

    This configuration limits requests to the /book GET endpoint to 5 per minute, as shown below.

    The Postman app returns a "429 Too Many Requests" response to a GET request to the URL
    A “429 Too Many Requests” response for the /book GET endpoint on Postman.

    How To Throttle Based on User ID and Sessions

    1. To rate limit using user_id and session parameters, update the configureRateLimiting function in the app/Providers/RouteServiceProvider file with the following additional limiters and variables:
    ...
    RateLimiter::for('user', function (Request $request) {
      return Limit::perMinute(10)->by($request->user()?->id ?: $request->ip());
    });
    RateLimiter::for('session', function (Request $request) {
      return Limit::perMinute(15)->by($request->session()->get('key') ?: $request->ip());
    });
    1. Finally, apply this code to the /book/{id} GET and /book POST routes in the routes/api.php file:
    Route::middleware(['throttle:user'])->group(function () {
      Route::get('/book/{id}', [BookController::class, 'getBook']);
    });
    Route::middleware(['throttle:session'])->group(function () {
      Route::post('/book', [BookController::class, 'createBook']);
    });

    This code limits requests using user_id and session, respectively.

    Additional Methods in Throttle

    Laravel Throttle features several additional methods for greater control over your rate-limiting implementation. These methods include:

    • attempt — Hits the endpoint, increments the hit count, and returns a boolean indicating whether the configured hit limit has been exceeded.
    • hit — Hits the Throttle, increments the hit count, and returns $this to enable another (optional) method call.
    • clear — Resets the Throttle count to zero and returns $this so you can make another method call if desired.
    • count — Returns the total number of hits to the Throttle.
    • check — Returns a boolean indicating whether the Throttle hit limit has been exceeded.
    1. To explore rate limiting using these methods, create a middleware app called CustomMiddleware using the command below:
    php artisan make:middleware CustomMiddleware
    1. Then, add the following import files to the newly created middleware file in app/Http/Middleware/CustomMiddleware.php:
    use GrahamCampbell\Throttle\Facades\Throttle;
    use App;
    1. Next, replace the content of the handle method with the following code snippet:
    $throttler = Throttle::get($request, 5, 1);
    Throttle::attempt($request);
    if(!$throttler->check()){
      App::abort(429, 'Too many requests');
    }
    return $next($request);
    1. In the app/Http/Kernel.php file, create an alias for this middleware app by updating the middlewareAliases array as follows.
    protected $middlewareAliases = [
    . . .
    'custom.throttle' => \App\Http\Middleware\CustomMiddleware::class, 
    ];
    1. Then, apply this middleware to the /custom-route in the routes/api.php file:
    Route::middleware(['custom.throttle'])->group(function () {
      Route::get('/custom-route', [BookController::class, 'getBooks']);
    });

    The custom middleware just implemented checks if the throttle limit has been exceeded using the check method. If the limit is exceeded, it responds with a 429 error. Otherwise, it allows the request to continue.

    How To Deploy the Application to the Kinsta Server

    Now that you’ve explored how to implement rate limiting in a Laravel application, deploy the app to the Kinsta server to make it accessible globally.

    1. Start by pushing the updated code to GitHub, GitLab, or Bitbucket.
    2. From your Kinsta dashboard, click the Add service button and select Application from the list. Link your Git account to your Kinsta account and select the correct repository to deploy.
    3. Under Basic details, name the application and choose your preferred data center. Also, ensure you added the necessary application environment variables. These correspond to the variables present in your local .env file: the APP_KEY and the database configuration variables.

    The
    Application details on MyKinsta.

    1. Click the Continue button to select the build environment variables. You can leave the default values, as Kinsta auto-fills the necessary parameters.
    2. On the Processes tab, you can leave the default values or enter a name for your process. You can also select the pod and instance sizes on this tab.
    3. Finally, the Payment tab displays a summary of your selections. Add your preferred payment option to finalize the process.
    4. Once complete, click the Applications tab to view a list of deployed applications.
    5. Click the application name to view its deployment details, as shown below. You can use the application’s URL to access it.

    The MyKinsta "Deployments" tab displays details about the deployed applications.
    Deployment details on MyKinsta dashboard.

    How To Test the Application

    1. To test the application locally, use the php artisan serve command.

    This command makes your application browser accessible at http://localhost:8000. You can test the API endpoints to which you implemented rate limiting from here by making repeated calls to trigger the rate limit functionality.

    The Kinsta server displays an Access Forbidden response because you haven’t added configuration details that direct Kinsta on how to serve the application. Add these details now.

    1. Create a .htaccess file in your app’s root directory and add the following code to the file:
     <IfModule mod_rewrite.c>
      RewriteEngine On
      RewriteRule ^(.*)$ public/$1 [L]
    </IfModule>
    1. Push these changes to GitHub and Kinsta auto-deploys to enact the change.
    2. Now, open the application using the provided URL and ensure you see the Laravel welcome page.

    You can now test the API endpoints to which you implemented rate limiting using Postman by making repeated calls until you’ve reached the configured limit. You receive a 429 Too Many Requests response after exceeding the limit.

    Summary

    Integrating rate-limiting functionalities into a Laravel API helps control the rate at which users consume an application’s resources. Rate limiting helps you to provide a reliable user experience without under and over-spending. It also ensures the application’s underlying infrastructure remains functional and efficient.

    You can also check out the Kinsta blog to learn more about other exciting concepts on Laravel and other web technologies. The affordable and seamless hosting services are highly recommended for your application and team’s needs.

Marcia Ramos Kinsta

I'm the Editorial Team Lead at Kinsta. I'm a open source enthusiast and I love coding. With more than 7 years of technical writing and editing for the tech industry, I love collaborating with people to create clear and concise pieces of content and improve workflows.