DEV Community

Jonathan Ruiz
Jonathan Ruiz

Posted on

6

Laravel 11 API Rest Auth with jwt-auth

Installing via composer



composer require tymon/jwt-auth


Enter fullscreen mode Exit fullscreen mode

Publishing the config



php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"


Enter fullscreen mode Exit fullscreen mode

This command will create a file in config/jwt.php
There you can modify the default config like the expiration time of the token

Generating the secret key



php artisan jwt:secret


Enter fullscreen mode Exit fullscreen mode

This command will add the key JWT_SECRET in your .env

Adding api guard
Inside the config/auth.php
Make the following changes



'defaults' => [
    'guard' => env('AUTH_GUARD', 'api'),
    'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
],


Enter fullscreen mode Exit fullscreen mode


'guards' => [
    'web' => [
         'driver' => 'session',
         'provider' => 'users',
    ],
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],


Enter fullscreen mode Exit fullscreen mode

Updating the User model



use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject


Enter fullscreen mode Exit fullscreen mode

Adding the require methods



public function getJWTIdentifier()
    {
        return $this->getKey();
    }
public function getJWTCustomClaims()
    {
        return [];
    }


Enter fullscreen mode Exit fullscreen mode

Creating the UserController



php artisan make:controller UserController --api --model=User


Enter fullscreen mode Exit fullscreen mode

Defining the store method



public function store(Request $request)
{
    $data = $request->validate([
        'name' => 'required',
        'email' => 'required|email|unique:users',
        'password' => 'required|min:6',
    ]);
    $data['password'] = bcrypt($data['password']);
    $user = User::create($data);
    return response()->json($user, 201);
}


Enter fullscreen mode Exit fullscreen mode

Defining the me method



public function me()
{
    return response()->json(auth()->user());
}


Enter fullscreen mode Exit fullscreen mode

Creating the AuthController



php artisan make:controller AuthController


Enter fullscreen mode Exit fullscreen mode

Defining the login method



public function login(Request $request)
{
    $credentials = $request->validate([
        'email' => 'required|email',
        'password' => 'required'
    ]);
    $token = auth()->attempt($credentials);

    if (!$token) {
        return response()->json([
            'status' => 401,
            'message' => 'Credenciales incorrectas'
        ], 401);
    }

    return response()->json([
        'token' => $token,
        'user' => auth()->user(),
        'expire_in' => auth()->factory()->getTTL() * 60
    ]);
}


Enter fullscreen mode Exit fullscreen mode

Defining the me method



public function me()
{
    return response()->json(auth()->user());
}


Enter fullscreen mode Exit fullscreen mode

Creating GuestMiddleware



php artisan make:middleware GuestMiddleware


Enter fullscreen mode Exit fullscreen mode

This command will create the middleware in app/Http/Middlewares
import use Illuminate\Support\Facades\Auth;



public function handle(Request $request, Closure $next, ...$guards): Response
{
    if (Auth::guard($guards)->check()) {
        abort(401, 'You are not allowed to access this resource');
    }
    return $next($request);
}


Enter fullscreen mode Exit fullscreen mode

This middleware will prevent the users authenticated can access to some routes like login route

Creating AuthMiddleware



php artisan make:middleware AuthMiddleware


Enter fullscreen mode Exit fullscreen mode

This command will create the middleware in app/Http/Middlewares
import use Illuminate\Support\Facades\Auth;



public function handle(Request $request, Closure $next, ...$guards): Response
{
    if (!Auth::guard($guards)->check()) {
        abort(401, 'You are not allowed to access this resource');
    }
    return $next($request);
}


Enter fullscreen mode Exit fullscreen mode

This middleware will prevent the users unauthenticated can access to some routes like me route

Defining the routes



use App\Http\Controllers\UserController;
use App\Http\Controllers\AuthController;
use App\Http\Middleware\GuestMiddleware;
use App\Http\Middleware\AuthMiddleware;

Route::middleware(GuestMiddleware::class)->group(function () {
    Route::post('login', [AuthController::class, 'login'])->name('login');
});
Route::middleware(AuthMiddleware::class)->group(function () {
    Route::get('me', [AuthController::class, 'me'])->name('me');
});

Route::apiResource('users', UserController::class);


Enter fullscreen mode Exit fullscreen mode

Creating the AuthTest



php artisan make:test AuthTest


Enter fullscreen mode Exit fullscreen mode

This command will create a file in tests/Feature



use Illuminate\Foundation\Testing\RefreshDatabase;
use PHPUnit\Framework\Attributes\Test;
class AuthTest extends TestCase
{
    use RefreshDatabase;
    private User $user;
    protected function setUp(): void
    {
        parent::setUp();
        $this->user = User::create([
            'name' => 'User',
            'email' => 'user@gmail.com',
            'password' => '1234',
        ]);
    }
}


Enter fullscreen mode Exit fullscreen mode

Tests methods



#[Test]
public function should_create_a_user(): void
{
    $data = [
        'name' => 'Test',
        'email' => 'test@gmail.com',
        'password' => '1234',
    ];

    $response = $this->postJson(route('users.store'), $data);

    $response->assertStatus(201);
    $this->assertDatabaseHas('users', ['email' => 'test@gmail.com']);
}

#[Test]
public function should_login(): void
{
    $data = [
        'email' => $this->user->email,
        'password' => '1234',
    ];
    $response = $this->postJson(route('login'), $data);

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

#[Test]
public function should_not_login(): void
{
    $data = [
        'email' => $this->user->email,
        'password' => '12345',
    ];
    $response = $this->postJson(route('login'), $data);
    $response->assertStatus(401);
}

#[Test]
public function should_return_user_authenticated(): void
{
    $response = $this->actingAs($this->user)->getJson(route('me'));
    $response->assertStatus(200);
    $response->assertJsonStructure(['id', 'name', 'email']);
    $response->assertJson(['id' => $this->user->id]);
}


Enter fullscreen mode Exit fullscreen mode

Remove comments in the file phpunit.xml



<env name="APP_ENV" value="testing"/>
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_STORE" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="MAIL_MAILER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="TELESCOPE_ENABLED" value="false"/>


Enter fullscreen mode Exit fullscreen mode

Running the tests



php artisan test --filter AuthTest


Enter fullscreen mode Exit fullscreen mode

Image description

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay