DEV Community

Jonathan Ruiz
Jonathan Ruiz

Posted on

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

Top comments (0)