How to Set API Rate Limiting in Laravel

We are going to continue with our discussion on Laravel and website security and introduce an API endpoint. I will also explore Laravel’s rate limiting functionality. To set things in proper context, i will use the to-do app developed in the previous article.

What is rate limiting?

Rate limiting is the control of the number of requests per unit time. It can be applied to ports, IPs, routes, etc. when used correctly, it can efficiently block out malicious bots. In the case of our API, it can mitigate DOS attacks , thus, making our API accessible without downtime for legitimate users.

Note, rate limiting can also be done via a firewall. For example using IPTables on Debian based systems:

PHP

1

2

3

4

5

>iptables-IINPUT-ptcp--dport80-ieth0-mstate--state NEW-mrecent\

--set

>iptables-IINPUT-ptcp--dport80-ieth0-mstate--state NEW-mrecent\

--update--seconds60--hitcount10-jDROP

This will limit hits to port 80, 10 times per minute. This approach, however, makes it difficult, if not impossible to only apply rate limiting to the API routes and not the entire site itself. Fortunately, Laravel (versions 5.2 and above) has built in API Throttling Middleware for this exact purpose.

Laravel Rate Limiting

First, let’s create the API.

The idea is to be able to add a task by using an API route. This should be simple enough. We just add two routes (to list tasks and add tasks) and instead of returning a template, we return a JSON response.

This will cap requests made by an IP to 3 every 10 minutes. Next time the user hits the API from the same IP, the following response will be returned:

PHP

1

2

3

4

5

6

7

8

9

...

<X-RateLimit-Limit:3

<X-RateLimit-Remaining:0

<Retry-After:599

...

Too Many Attempts.

The key to rate limiting is finding the right balance. In our sample “To-do tasks” app, if 3 tasks every ten minutes seems too restrictive, we could change it to 3 tasks per minute with the following (omitting the second number, since by default it is set to 1 minute , i.e. ‘middleware’ => ‘throttle’, will limit 10 requests per minute).

PHP

1

2

3

4

5

Route::group(['prefix'=>'api','middleware'=>'throttle:3'],function(){

...

});

Using fields other than IP to throttle

Many institutions and ISP’s use NAT’d solutions. Hence, it is not advisable to limit an entire group of people just because one of them is abusing the API. If we want to throttle by something unit other than IP, all we have to do is extend the base ThrottleRequests class and override the resolveRequestSignature function:

Replace the $request->ip() field with some other field. For example, to throttle using the session id as the unique key, add:

PHP

1

$request->session()

Or if you want to throttle by using the user_id passed into the request,

PHP

1

$request->input('user_id')

Or even the API Key

PHP

1

$request->header(‘API-KEY’)

The only requirement here is that the field in question be unique between users. But that’s about it. We have our API rate limiting in place.If you need further clarification or wish to share your opinion, do leave a comment below.

Dynamic Rate Limiting

With the Laravel 5.6, you can specify maximum number of requests based on the attribute of authenticated User’s model, using the feature of dynamic rate limiting.

Prerequisites

For the purpose of this tutorial, I assume that you have a Laravel application installed on a web server. My setup is:

Laravel 5.5

PHP 7.1

MySQL

Node.js with NPM

In my experience, server management issues could be a serious roadblock for developers. I avoid these roadblocks by opting for Cloudways. Cloudways offers a great development stack (known as ThunderStack) to host Laravel projects and takes care of all server level problems. You can try out Cloudways for free by signing for an account.

Laravel simplifies the process of limiting the number of requests a client could make for a particular action. Consider the following snippet from the Laravel Docs:

1

2

3

4

5

Route::middleware('auth:api','throttle:60,1')->group(function(){

Route::get('/user',function(){

//

});

});

In the above snippet, the authenticated user can only hit the mentioned routes 60 times (and more!). This is handled by the throttle middleware. While this is great, in many cases, this is not enough in many cases. In many cases, dynamic rate limiting is an essential requirement of the project.

In the above snippet, the middleware is used once again. But the request is not defined there. Rather, the attribute name is passed. In the context of the snippet, rate_limit is a field in the user’s table that records the number of requests as an integer. Using this process, developers could easily define and control the number of requests for individual users. A popular use case that comes to mind is limiting access to particular resources based on the user-opted subscription plans.

Enable/Disable Rate Limiting:

The API rate limiting middleware is enabled and applied to all the Container Endpoints by default. To disable it, set API_RATE_LIMIT_ENABLED to false in the .env file.

Laravel Throttle Package

Created by Graham Campbell, Laravel Throttle is an exclusively built package that perform rate limiting in Laravel 5. It requires PHP 7.x version for its proper functioning and supports optional configuration. To start working, you need to publish all vendor assets through executing PHP artisan command which will create throttle.php file inside your app.

Conclusion

Rate limiting is an important option that completely changes the project structure (for the better). Developers could easily setup and control the frequency of access to resources through a simple in-code process. Let me know if you need further clarification about Laravel rate limiting.

FAQ’s

Q1 How to implement the Laravel Throttle Request middleware in Laravel 5.5?
A: Throttle Request refers to a process in which an authenticated user is allowed to hit the application maximum time. After that, the user’s session is either expired or is denied access to the application. Throttle Request could be implemented in Laravel as shown below:

Look at RateLimit::hit() code. It’s pretty clear:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

/**

* Increment the counter for a given key for a given decay time.

*

* @param string $key

* @param float|int $decayMinutes

* @return int

*/

publicfunctionhit($key,$decayMinutes=1)

{

$this->cache->add(

$key.':timer',$this->availableAt($decayMinutes *60),$decayMinutes

);

$added=$this->cache->add($key,0,$decayMinutes);

$hits=(int)$this->cache->increment($key);

if(!$added&&$hits==1){

$this->cache->put($key,1,$decayMinutes);

}

return$hits;

}

If you want to limit some activity by 10 hits per 5 minutes, than decay Minutes must be 5

Q2 How to setup different rate limits for different paths ?
A: First edit the Kernel.php file and comment out its default line 40 so that it doesn’t conflicts with each middleware group. You can also modify the middleware by including second parameter that will define how long the waiting period would be until the next request could arrive. (e.g. throttle:60,1)

Q3 How to disable rate limiter in Laravel?

A: For disabling the rate limiter in Laravel, first go to the app/Http/Kernel.php. There you will find default throttle limit defined by Laravel for all api routes. Just comment out that code to disable it completely.