Welcome to CodeCrew Infotech

shape shape
Shape Shape Shape Shape
Blog

Securing Your Laravel API with JWT Authentication and Swagger Documentation

Swagger is a popular tool for documenting and testing RESTful APIs. It allows you to generate interactive documentation for your API endpoints, making it easier for developers to understand and interact with your API.

Here are the steps to integrate Swagger into your Laravel 11 application:

1. Create a project:

Now, open a terminal and run this command:

composer create-project laravel/laravel swagger-laravel

After Setup Project:

cd swagger-laravel

2. Database Configuration:

In the second step, configuring database credentials for the Laravel Jwt Auth app is essential. Simply update the .env file located in the root directory of the application.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_db_name
DB_USERNAME=your_db_username
DB_PASSWORD=your_db_password

Migrate the database using the following command:

php artisan migrate

3. Install the required packages: -

First, you need to install the required packages for Swagger integration. Run the following command in your terminal:
Now, open terminal

composer require --dev darkaonline/l5-swagger

To publish the configuration file for a package in Laravel, you can use the vendor:publish Artisan command with the

 

php artisan vendor:publish --provider="L5Swagger\L5SwaggerServiceProvider"

4. Install the Laravel tymon/jwt-auth package: -

Now, open terminal

composer require tymon/jwt-auth

To publish the configuration file for a package in Laravel, you can use the vendor:publish Artisan command with the

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

5. Generate a secret key:

To generate a secret key for JWT authentication in Laravel, you can use the php artisan jwt:secret Artisan command. This command generates a unique secret key specifically for JWT authentication in your Laravel application.

Here's the command:

php artisan jwt:secret

6. Deprecated in Laravel 11: install:api

The php artisan install:api command in Laravel 11 has been deprecated. Here's what you need to know:

What php artisan install:api did (Laravel versions < 11):

  • This command is used to perform several actions related to API development:
  • API routes file creation: It created a file named api.php in the routes directory, specifically for defining API routes.
  • Package installation: In some versions, it might have installed packages like tymon/jwt-auth to facilitate API authentication.
  • Database migrations: It could have triggered the migration process to create database tables required for authentication or other API functionality.
php artisan install:api

7. Update the user model.

In Laravel, updating your user model for JWT authentication typically requires a few modifications. Here's a basic outline of what you might need to do:

1. Implement the JWTSubject interface: Your user model should implement the Tymon\JWTAuth\Contracts\JWTSubject interface. This requires you to define two methods: getJWTIdentifier() and getJWTCustomClaims(). These methods help the Laravel JWT Auth package determine the identity and additional claims associated with the user.

To begin, open your 'app/Models/User.php' file and make the necessary modifications to the existing code.

<?php

namespace App\Models;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements JWTSubject
{
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass-assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }

    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }
}

8. Update Auth.php:

To update the auth.php configuration file in Laravel for JWT authentication, you typically need to make changes to the 'guards' and 'providers' sections. Here's how you can modify it:

  • Guards Configuration: Add a new guard for JWT authentication. This guard will use the jwt driver provided by the jwt-auth package.
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],
  • Providers Configuration: Ensure that the 'users' provider is set up to retrieve user information from the appropriate model (typically the App\Models\User model).
'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],
],

9. Modified Controller:

To begin, open your 'app/Http/Controller.php' file and make the necessary modifications to the existing code.

 

php artisan make:controller AuthController

10. Make a controller.

To create an AuthController in Laravel, you can use the php artisan command-line tool. Here's how you can generate the controller:

php artisan make:controller AuthController

This command will create a new file named AuthController.php in the app/Http/Controllers directory, containing a basic controller structure. You can then customize this controller to handle authentication requests using JWT according to your requirements and integrate Swagger documentation as needed.

To begin, open your 'app/Models/AuthController.php' file and make the necessary modifications to the existing code.

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Tymon\JWTAuth\Facades\JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use Illuminate\Support\Facades\Auth;

class AuthController extends Controller
{

    /**
     * Register a new user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function register(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|unique:users', // Ensure unique email
            'password' => 'required|string|min:8',
        ]);

        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);
        }

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);


        return response()->json(['message' => 'User created successfully'], 201);
    }

    /**
     * Authenticate the user and return a JWT token if valid credentials are provided.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'email' => 'required|email',
            'password' => 'required|string|min:6',
        ]);
        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);
        }
        $credentials = request(['email', 'password']);

        if (!$token = auth()->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }
        return $this->respondWithToken($token);
    }
    /**
     * Respond with a JWT token.
     *
     * @param  string  $token
     * @return \Illuminate\Http\JsonResponse
     */
    protected function respondWithToken($token)
    {
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth('api')->factory()->getTTL() * 60
        ]);
    }
    /**
     * Get the authenticated user's profile.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function profile(Request $request)
    {
        // Retrieve the authenticated user
        $user = Auth::user();

        // Return the user's profile information
        return response()->json($user);
    }
}

11. Create middleware:

Now let us use the following command to create middleware:.

php artisan make:middleware CheckAuth

To begin, open your 'CheckAuth.php' file and make the necessary modifications to the existing code.

app/Http/Middleware/CheckAuth.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class CheckAuth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        if (!auth()->user() && !$request->bearerToken()) {
            return response()->json(['error' => 'Unauthenticated'], 401);
        }
        return $next($request);
    }
}

12. Register Middleware:

Open the 'app.php' file.

bootstrap/app.php

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__, '/../routes/web.php',
        api: __DIR__, '/../routes/api.php',
        commands: __DIR__ . '/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->alias([
            'checkAuth' => \App\Http\Middleware\CheckAuth::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

13. Add Routes:

To add the route for the profile endpoint in your routes/api.php file, you can do the following:

To begin, open your 'routes/api.php' file and make the necessary modifications to the existing code.

<?php

use App\Http\Controllers\AuthController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);

Route::middleware('checkAuth')->group(function () {
    Route::get('/me', [AuthController::class, 'getUser']);
});

14. Generate Swagger Documentation:

After annotating your API routes, you can generate the Swagger documentation by running the following command:

php artisan l5-swagger:generate

15. Run the Laravel Project:

run the following command:

php artisan serve

16. Access Swagger UI:

Finally, you can access the Swagger UI by visiting the following URL in your browser:

localhost:8000/api/documentation

So, let's follow the steps, and you will get the below layout:

Conclusion:-

Implementing JWT authentication and Swagger documentation provides a robust solution for securing your Laravel API. By integrating JWT for authentication and Swagger for documentation, you enhance the security of your API endpoints while ensuring clear and comprehensive documentation. This combination allows for secure communication between clients and your API while also facilitating ease of understanding and usage for developers.

Thank you...