Laravel REST API Authentication & Best Practices: Complete Guide (2026)

Quick Answer — Laravel API Authentication

Use Laravel Sanctum for most REST APIs. Install it, run migrations, then issue tokens on login:

$token = $user->createToken('auth_token')->plainTextToken;

Protect routes with middleware(['auth:sanctum']). The client sends the token as Authorization: Bearer {token} on every request. Full setup walkthrough below.

Building robust REST APIs is one of the most in-demand Laravel skills in 2026. Getting authentication right, returning consistent responses, and following RESTful conventions from day one saves enormous pain when your API grows.

This guide covers everything from project setup to production-grade authentication — the same patterns I use across 10+ production APIs.

1. Project Setup & Configuration

# Create new Laravel project composer create-project laravel/laravel api-project cd api-project # Install Sanctum for API authentication composer require laravel/sanctum php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider" php artisan migrate
// config/app.php — always use UTC for APIs 'timezone' => 'UTC', // .env API_VERSION=v1 API_RATE_LIMIT=60

2. API Routing & Versioning

Always version your API from day one. Changing /api/products to /api/v2/products later breaks every client. Starting with /api/v1/ costs nothing upfront.

// routes/api.php use App\Http\Controllers\Api\V1\AuthController; use App\Http\Controllers\Api\V1\UserController; use App\Http\Controllers\Api\V1\ProductController; Route::prefix('v1')->group(function () { // Public routes — no auth required Route::post('/register', [AuthController::class, 'register']); Route::post('/login', [AuthController::class, 'login']); // Protected routes — Sanctum auth required Route::middleware(['auth:sanctum'])->group(function () { Route::post('/logout', [AuthController::class, 'logout']); Route::get('/profile', [UserController::class, 'profile']); Route::apiResource('products', ProductController::class); }); });

3. Authentication with Sanctum

Laravel Sanctum is the right choice for most REST APIs — it's lightweight, official, and handles token-based authentication cleanly. Here's the full implementation:

// app/Http/Controllers/Api/V1/AuthController.php class AuthController extends Controller { public function register(RegisterRequest $request) { $user = User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), ]); $token = $user->createToken('auth_token')->plainTextToken; return $this->successResponse([ 'user' => $user, 'token' => $token, 'token_type' => 'Bearer', ], 'User registered successfully', 201); } public function login(LoginRequest $request) { if (!Auth::attempt($request->only('email', 'password'))) { return $this->errorResponse('Invalid credentials', 401); } $user = Auth::user(); $token = $user->createToken('auth_token')->plainTextToken; return $this->successResponse([ 'user' => $user, 'token' => $token, 'token_type' => 'Bearer', ], 'Login successful'); } public function logout(Request $request) { $request->user()->currentAccessToken()->delete(); return $this->successResponse(null, 'Logged out successfully'); } }
How the client uses the token: After login, store the token and send it on every request as Authorization: Bearer {token}. Laravel's auth:sanctum middleware validates it automatically.
# Example request with Bearer token curl -X GET https://yourapi.com/api/v1/profile \ -H "Authorization: Bearer 1|abc123yourtoken" \ -H "Accept: application/json"

4. Request Validation

Always use Form Requests for validation — never validate inline in controllers. It keeps controllers clean and makes validation reusable.

// app/Http/Requests/RegisterRequest.php class RegisterRequest extends FormRequest { public function authorize(): bool { return true; } public function rules(): array { return [ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users,email', 'password' => 'required|string|min:8|confirmed', ]; } public function messages(): array { return [ 'email.unique' => 'This email is already registered.', 'password.confirmed' => 'Password confirmation does not match.', ]; } }

5. Consistent Error Handling

Nothing frustrates API consumers more than inconsistent response formats. Build a base controller with standard response methods used everywhere:

// app/Http/Controllers/Controller.php class Controller extends BaseController { protected function successResponse($data, string $message = 'Success', int $code = 200) { return response()->json([ 'success' => true, 'message' => $message, 'data' => $data, ], $code); } protected function errorResponse(string $message, int $code = 400, $errors = null) { return response()->json(array_filter([ 'success' => false, 'message' => $message, 'errors' => $errors, ]), $code); } }
// app/Exceptions/Handler.php — global JSON error handling public function render($request, Throwable $exception) { if ($request->expectsJson()) { if ($exception instanceof ModelNotFoundException) { return response()->json(['success' => false, 'message' => 'Resource not found'], 404); } if ($exception instanceof AuthenticationException) { return response()->json(['success' => false, 'message' => 'Unauthenticated'], 401); } if ($exception instanceof ValidationException) { return response()->json([ 'success' => false, 'message' => 'Validation failed', 'errors' => $exception->errors(), ], 422); } } return parent::render($request, $exception); }

6. API Documentation

Use Scribe for simple auto-generated docs, or L5-Swagger for full OpenAPI/Swagger support. Always include a Postman collection for your API consumers — it removes the biggest barrier to adoption.

7. Testing Your API

// tests/Feature/AuthTest.php class AuthTest extends TestCase { use RefreshDatabase; public function test_user_can_register(): void { $response = $this->postJson('/api/v1/register', [ 'name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'password123', 'password_confirmation' => 'password123', ]); $response->assertStatus(201) ->assertJsonStructure([ 'success', 'message', 'data' => ['user', 'token', 'token_type'] ]); $this->assertDatabaseHas('users', ['email' => 'john@example.com']); } public function test_user_can_login(): void { $user = User::factory()->create(['password' => Hash::make('password123')]); $response = $this->postJson('/api/v1/login', [ 'email' => $user->email, 'password' => 'password123', ]); $response->assertStatus(200) ->assertJsonPath('success', true) ->assertJsonStructure(['data' => ['token']]); } }

8. Performance Tips

The five highest-impact performance improvements for Laravel APIs: eager loading to eliminate N+1 queries, Redis caching for frequently accessed data, rate limiting to protect against abuse, API Resources for consistent data transformation, and offloading heavy operations to queue jobs.

// Add rate limiting to routes/api.php Route::middleware(['auth:sanctum', 'throttle:60,1'])->group(function () { Route::apiResource('products', ProductController::class); }); // Use API Resources for consistent response format php artisan make:resource ProductResource // Eager load to prevent N+1 — always check with Laravel Debugbar $products = Product::with(['category', 'tags'])->paginate(15);

9. Conclusion

The foundation of a good Laravel REST API is consistent authentication with Sanctum, versioned routes, Form Request validation, and standardised JSON responses. Build these in from day one — retrofitting them into a large codebase later is far more painful than getting them right upfront.

For the full authentication comparison, see Does Laravel Sanctum Use JWT? Sanctum vs JWT Explained. For handling background tasks in your API, check the Laravel Queues & Jobs guide.

Need Help Building Your Laravel API?

I've built and shipped 10+ production APIs — e-commerce platforms, SaaS backends, and payroll systems. Happy to help you build something solid.

Based in Bangladesh · Remote worldwide · Fast turnaround

About the Author

Kamruzzaman Polash — Software Engineer specialising in Laravel, REST APIs, and scalable backend systems. 10+ projects delivered for clients worldwide.