SyntaxStudy
Sign Up
Laravel API Authentication and Rate Limiting
Laravel Beginner 1 min read

API Authentication and Rate Limiting

Securing a Laravel API typically involves either Sanctum (simple token auth) or Passport (full OAuth2). For first-party SPAs and mobile apps, Sanctum is the recommended choice. Token-protected routes use the auth:sanctum middleware. API routes that are public use no middleware, while routes requiring specific token abilities use middleware like auth:sanctum combined with ability checks. Custom rate limiters allow fine-grained control over how many requests a client can make. Limiters are registered with RateLimiter::for() and can be applied per-user (keyed by user ID) or per-IP for guests. Multiple limits can be applied as an array, providing both per-minute and per-day caps. When a limit is exceeded, Laravel automatically responds with a 429 Too Many Requests status. Caching API responses dramatically improves performance for read-heavy endpoints. The Cache facade and HTTP cache headers work together. Eloquent's remember() via cache drivers can cache query results. For HTTP caching, the response()->header('Cache-Control', 'public, max-age=60') instructs CDNs and browsers to cache the response. ETag-based conditional requests prevent serving unchanged data using If-None-Match headers.
Example
<?php
// app/Providers/RouteServiceProvider.php (or AppServiceProvider)
// Registering custom rate limiters

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;

RateLimiter::for('api', function (Request $request) {
    return $request->user()
        ? Limit::perMinute(120)->by($request->user()->id)
        : Limit::perMinute(20)->by($request->ip());
});

RateLimiter::for('uploads', function (Request $request) {
    return [
        Limit::perMinute(5)->by($request->user()?->id ?: $request->ip()),
        Limit::perDay(50)->by($request->user()?->id ?: $request->ip()),
    ];
});

// routes/api.php
Route::middleware(['auth:sanctum', 'throttle:api'])->group(function () {
    Route::apiResource('posts', \App\Http\Controllers\Api\V1\PostController::class);
});

Route::middleware('throttle:uploads')->post('/media', [
    \App\Http\Controllers\Api\MediaController::class, 'store',
]);

// Caching a response in a controller
public function index(): \Illuminate\Http\JsonResponse
{
    $posts = cache()->remember('api.posts', 60, fn() =>
        \App\Models\Post::published()->with('user')->paginate(20)
    );
    return PostResource::collection($posts)->response();
}