Laravel 11 JSON Web Token(JWT) API Authentication Example Tutorial

Jun 15, 2024 | Laravel 11 Laravel


Hello Dev,

In this post, I will guide you through setting up API Authentication using JWT tokens in a Laravel 11 application. We'll start from the basics, covering APIs, REST APIs, and the concept of JWT (JSON Web Token), which is crucial for secure information transmission and authorization between applications.

What is API?

An API (Application Programming Interface) facilitates communication between different software programs. It's essential for developing web and mobile applications, enabling them to interact and exchange data.

What is JWT?

JWT, or JSON Web Token, is a compact and self-contained method (defined by RFC 7519) for securely transmitting information between parties as a JSON object. JWT is widely used for purposes like Authorization and Information Exchange in modern web development.

1. Install Laravel 11 Application: Begin by setting up a Laravel 11 application environment.

2. Install API: Create and configure API routes and controllers.

3. Integrate JWT Authentication: Utilize the `php-open-source-saver/jwt-auth` package for JWT functionality.

4. Implement APIs: Develop APIs for user authentication tasks such as register, login, refresh token, profile management, and logout.

Follow the steps below to complete this example step-by-step, ensuring a comprehensive understanding of JWT-based API authentication in Laravel 11.

Step 1: Install Laravel

If you haven't already, create a new Laravel project:

composer create-project laravel/laravel example-app
Step 2: Enable API and Update Authentication Exception

By default, Laravel 11 does not have API routes enabled. To enable API routes, use the following command:

php artisan install:api

After enabling API routes, if a user is not authenticated, an exception will be thrown. To handle this and return a JSON response, update the `app.php` file.

Make necessary modifications in your `app.php` configuration file to ensure proper handling of unauthenticated requests with appropriate JSON responses.

bootstrap/app.php
<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Http\Request;

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) {
        //
    })
    ->withExceptions(function (Exceptions $exceptions) {
        $exceptions->render(function (AuthenticationException $e, Request $request) {
            if ($request->is('api/*')) {
                return response()->json([
                    'message' => $e->getMessage(),
                ], 401);
            }
        });
    })->create();
Step 3: Install and Setup JWT Auth package

In this step, we will install the `php-open-source-saver/jwt-auth` composer package.

composer require php-open-source-saver/jwt-auth

Next, publish the package configuration file:

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

Then, generate a secret key. This command will add JWT configuration values to your `.env` file:

php artisan jwt:secret

Now, proceed to update the authentication guard configuration file as needed.

Ensure to make these updates to configure JWT authentication properly in your Laravel application.

config/auth.php
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option defines the default authentication "guard" and password
    | reset "broker" for your application. You may change these values
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'api',
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | which utilizes session storage plus the Eloquent user provider.
    |
    | All authentication guards have a user provider, which defines how the
    | users are actually retrieved out of your database or other storage
    | system used by the application. Typically, Eloquent is utilized.
    |
    | Supported: "session"
    |
    */

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

    ...
Read Also: How To Generate PDF and Send Email in Laravel 11? Step 4: Update User Model

In the model, we start by implementing the `Tymon\JWTAuth\Contracts\JWTSubject` contract on the User Model. This involves implementing the `getJWTIdentifier()` and `getJWTCustomClaims()` methods as required by the contract.

app/Models/User.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use PHPOpenSourceSaver\JWTAuth\Contracts\JWTSubject; 

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

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

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

    /**
     * Get the attributes that should be cast.
     *
     * @return array
     */
    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 [];
    }
}
Step 5: Create API Routes

In this step, we will define API routes. Laravel utilizes the `api.php` file specifically for writing web service routes. Let's proceed by adding a new route to that file.

routes/api.php
<?php

use Illuminate\Support\Facades\Route;

use App\Http\Controllers\API\AuthController;
 
Route::group([
    'middleware' => 'api',
    'prefix' => 'auth'
], function ($router) {
    Route::post('/register', [AuthController::class, 'register']);
    Route::post('/login', [AuthController::class, 'login']);
    Route::post('/logout', [AuthController::class, 'logout'])->middleware('auth:api');
    Route::post('/refresh', [AuthController::class, 'refresh'])->middleware('auth:api');
    Route::post('/profile', [AuthController::class, 'profile'])->middleware('auth:api');
});
Read Also: How To Generate PDF and Send Email in Laravel 11? Step 6: Create Controller Files

In the next step, we have created two new controllers: `BaseController` and `AuthController`. These controllers are located within a new folder named "API" under the Controllers directory. Let's proceed to create both controllers:

app/Http/Controllers/API/BaseController.php
<?php
 
namespace App\Http\Controllers\API;
 
use Illuminate\Http\Request;
use App\Http\Controllers\Controller as Controller;
 
class BaseController extends Controller
{
    /**
     * success response method.
     *
     * @return \Illuminate\Http\Response
     */
    public function sendResponse($result, $message)
    {
        $response = [
            'success' => true,
            'data'    => $result,
            'message' => $message,
        ];
 
        return response()->json($response, 200);
    }
 
    /**
     * return error response.
     *
     * @return \Illuminate\Http\Response
     */
    public function sendError($error, $errorMessages = [], $code = 404)
    {
        $response = [
            'success' => false,
            'message' => $error,
        ];
 
        if(!empty($errorMessages)){
            $response['data'] = $errorMessages;
        }
 
        return response()->json($response, $code);
    }
}
app/Http/Controllers/API/AuthController.php
<?php

namespace App\Http\Controllers\API;
  
use App\Http\Controllers\API\BaseController as BaseController;
use App\Models\User;
use Validator;
use Illuminate\Http\Request;
  
class AuthController extends BaseController
{
 
    /**
     * Register a User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function register(Request $request) {

        $validator = Validator::make($request->all(), [
            'name' => 'required',
            'email' => 'required|email',
            'password' => 'required',
            'c_password' => 'required|same:password',
        ]);
     
        if($validator->fails()){
            return $this->sendError('Validation Error.', $validator->errors());       
        }
     
        $input = $request->all();
        $input['password'] = bcrypt($input['password']);
        $user = User::create($input);
        $success['user'] =  $user;
   
        return $this->sendResponse($success, 'User register successfully.');
    }
  
  
    /**
     * Get a JWT via given credentials.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login()
    {
        $credentials = request(['email', 'password']);
  
        if (! $token = auth()->attempt($credentials)) {
            return $this->sendError('Unauthorised.', ['error'=>'Unauthorised']);
        }
  
        $success = $this->respondWithToken($token);
   
        return $this->sendResponse($success, 'User login successfully.');
    }
  
    /**
     * Get the authenticated User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function profile()
    {
        $success = auth()->user();
   
        return $this->sendResponse($success, 'Refresh token return successfully.');
    }
  
    /**
     * Log the user out (Invalidate the token).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout()
    {
        auth()->logout();
        
        return $this->sendResponse([], 'Successfully logged out.');
    }
  
    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh()
    {
        $success = $this->respondWithToken(auth()->refresh());
   
        return $this->sendResponse($success, 'Refresh token return successfully.');
    }
  
    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function respondWithToken($token)
    {
        return [
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth()->factory()->getTTL() * 60
        ];
    }
}
Step: Run the Application

Now, to run the Laravel application, please type the following command and press enter:

php artisan serve
'headers' => [
    'Accept' => 'application/json',
    'Authorization' => 'Bearer '.$accessToken,
]
Refresh API: Verb:POST, URL:http://localhost:8000/api/auth/refresh Laravel 11 JSON Web Token(JWT) API Authentication Example Tutorial

Feel free to ask if you have any questions or need further clarification!



Tags :
#Laravel 11
#Laravel
ItErrorSolution.com

ItErrorSolution.com

"Hey there! I'm a full-stack developer and proud owner of ItErrorSolution.com, based right here in India. I love nothing more than sharing handy tips and tricks with my fellow developers through easy-to-follow tutorials. When it comes to coding, I'm all about PHP, Laravel, Angular, Vue, Node, JavaScript, jQuery, CodeIgniter, and Bootstrap – been hooked on them forever! I'm all about putting in the work and staying committed. Ready to join me on this journey to coding?"