DEV Community

Wendel Lopes
Wendel Lopes

Posted on

7 1

Laravel and JWT Authentication with custom model

  • Before we start, this is the first article i write in english, so apologize for any mistakes.

In this article, i will show you how to implement JWT authentication (using tymon/jwt-auth package) in a Laravel api, using a different model than the default (Users). At the end, a link to the repository will be available with the content of this article.

Portuguese version: https://dev.to/wenlopes/laravel-8-e-autenticacao-jwt-tymon-jwt-auth-com-model-customizada-2l7k

So let's go!

Installation

Run this command to install the package



composer require tymon/jwt-auth


Enter fullscreen mode Exit fullscreen mode

Publish the lib config file in your config folder, with the command



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


Enter fullscreen mode Exit fullscreen mode

Finally, let's generate the JWT secret, running the command (This command will add JWT_SECRET env in your .env file)



php artisan jwt:secret


Enter fullscreen mode Exit fullscreen mode

If you have questions about this step, this is the official link to package documentation

Model configuration

Now it's time to change our default model. For our example, let's use a Model called Employee.

For this, we gonna make a migration to create a table in our database, with same name of the Model.



php artisan make:migration create_employee_table --create=employee


Enter fullscreen mode Exit fullscreen mode

Our employee migration will have the same user migration structure that comes with the Laravel installation, but it difference will be a new column called "job_title".
Feel free to add new columns, but keep the "email" and "password" columns.



Schema::create('employee', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->string('password');
    $table->string('job_title');
    $table->timestamps();
});


Enter fullscreen mode Exit fullscreen mode

Remove user migration and run



php artisan migrate


Enter fullscreen mode Exit fullscreen mode

Create the Employee model



php artisan make:model Employee


Enter fullscreen mode Exit fullscreen mode

Important: In Employee model, you may need to add the $table variable, because when we create a test user in database (a little later in this article), Laravel will try to find the table name in plural, and it will cause error. If you already created the table in plural (employees), ignore this step.



protected $table = 'employee';


Enter fullscreen mode Exit fullscreen mode

The next step is to implement JWTSubject and extends Authenticatable class (Laravel) in our Model Employee. Finally, this will be our model content.

<?php
namespace App\Models;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class Employee extends Authenticatable implements JWTSubject
{
use HasFactory, Notifiable;
protected $table = 'employee';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
'job_title'
];
/**
* 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 [];
}
}
view raw Employee.php hosted with ❤ by GitHub

Very well, its time to configure our authentication provider. For that, you must access the config/auth.php file and add the 'employess' index in 'providers' array, containing the driver (for this example, we are using Eloquent) and its Model (employee)

image

Now let's set the "api" guard as our application default. In the same file, access the "defaults" array and set the default guard to "api"

image

We have finished our provider configuration and this should be the final content of config/auth.php.

<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| 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
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'employees'
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'employees' => [
'driver' => 'eloquent',
'model' => App\Models\Employee::class,
]
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,
];
view raw config-auth.php hosted with ❤ by GitHub

Creating Controller and Route

It's time to create an auth controller to test our implementation

Create an controller called AuthController, with same content of this link (official documentation from the package) and create a route in your routes/api.php file



use App\Http\Controllers\AuthController;

Route::post('auth/login', [AuthController::class, 'login'])->name('auth.login');


Enter fullscreen mode Exit fullscreen mode

To test our endpoint, lets create an employee in our database and use this data to authenticate

In the DatabaseSeeder file, insert this content in the run method



\App\Models\Employee::create([
    'name' => 'Usuário de teste',
    'email' => 'usuario@teste.com.br',
    'password' => bcrypt( 'senha123' ),
    'job_title' => 'Gerente administrativo'
]);


Enter fullscreen mode Exit fullscreen mode

And run this command:



php artisan db:seed


Enter fullscreen mode Exit fullscreen mode

Finally, use an API client (Postman, Insomnia...) and consume the api/auth/login login route, passing the email and password defined in the seeder. If everything work's fine, the result will be something like this:

image

So it's done! Your authentication with an custom model is working.

You can find the repository with this implementation through this link. In the repository, i'm using Docker as infra, with Nginx, Mysql and Laravel in version 8. Also, i implemented the pattern Strategy to return failed authentication messages and expired token response (in this case, a new valid token is returned).

So, that's all. If you have any questions, please comment and i will respond. Thank's for your attention.

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay