JWT Authentication with Laravel

Table of Contents

ℹ️ Note

While solutions like tymondesigns/jwt-auth (Laravel) or LexikJWTAuthenticationBundle (Symfony) are popular, we recommend adopting open standards such as OpenID Connect (OIDC) for robust, scalable, and interoperable authentication.

For comprehensive details on authentication, refer to our Laravel Authentication documentation.

# Setup Instructions

  1. Install
    Follow the official installation guide of Laravel Passport to implement OpenID Connect (OIDC) standards in your Laravel application. Alternatively, if you prefer an ad-hoc solution, you can use tymondesigns/jwt-auth to set up JWT authentication in your Laravel project.

  2. Configure Authentication
    Refer to the Authentication section of our documentation to properly configure and secure your API with JWT tokens.

💡 Tip

Use Laravel middlewares with API Platform such as auth:api to restrict access to certain endpoints, ensuring only authenticated users can access them.

By following these steps, you can set up a secure and scalable JWT-based authentication system in your Laravel application.

# Testing

To verify your authentication setup using ApiTestCase, you can write a test method tailored to your preferred testing framework. Here’s how you can approach it for both Pest and PHPUnit:

ℹ️ Note

Ensure your routes (/api/auth) and authentication mechanisms are configured to match your application’s implementation.

# Test with Pest

<?php

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('authenticates a user and tests protected endpoints', function () {
    // Create a user
    $user = User::factory()->create([
        'email' => '[email protected]',
        'password' => bcrypt('$3CR3T'), // Hash the password
    ]);

    // Retrieve a token
    $response = $this->postJson('/api/auth', [
        'email' => '[email protected]',
        'password' => '$3CR3T',
    ]);

    $response->assertStatus(200)
        ->assertJsonStructure(['token']);

    $token = $response->json('token');

    // Test not authorized
    $this->getJson('/api/greetings')
        ->assertStatus(401);

    // Test authorized
    $this->withHeader('Authorization', "Bearer $token")
        ->getJson('/api/greetings')
        ->assertStatus(200);
});

# Test with PHPUnit

<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AuthenticationTest extends TestCase
{
    use RefreshDatabase;

    public function testLogin(): void
    {
        $user = User::factory()->create([
            'email' => '[email protected]',
            'password' => bcrypt('$3CR3T'), // Hash the password
        ]);

        // Retrieve a token
        $response = $this->postJson('/api/auth', [
            'email' => '[email protected]',
            'password' => '$3CR3T',
        ]);

        $response->assertStatus(200)
            ->assertJsonStructure(['token']);

        $token = $response->json('token');

        // Test not authorized
        $this->getJson('/api/greetings')
            ->assertStatus(401);

        // Test authorized
        $this->withHeader('Authorization', "Bearer $token")
            ->getJson('/api/greetings')
            ->assertStatus(200);
    }
}

You can also help us improve the documentation of this page.

Made with love by

Les-Tilleuls.coop can help you design and develop your APIs and web projects, and train your teams in API Platform, Symfony, Next.js, Kubernetes and a wide range of other technologies.

Learn more

Copyright © 2023 Kévin Dunglas

Sponsored by Les-Tilleuls.coop