In Laravel, we can use authentication systems like Sanctum, and Passport. Still, Passport is one of the most popular authentication systems in Laravel. Most of the developer like to do authentication using Laravel Passport because of its extraordinary features. Like if you want to authenticate machine to machine, Passport is one of the favorite tools to use. So without a further delay, let's jump into code.
In this tutorial, we are using the latest version of Laravel which is Laravel 11.
First of all, let's create a project in Laravel using the following command.
composer create-project laravel/laravel passport-authentication
So, we created a brand new Laravel project. Now if you go to the route directory will not find any api.php
file. Because, from Laravel 11 API will not come by default. If we want API we need to install it manually. Before setting up Laravel Passport, make sure you set up your .env
file with your database and other credentials. Now migrate the database using the following command.
php artisan migrate
Now let's install Laravel Passport using the following command.
php artisan install:api --passport
So we have installed Laravel Passport successfully. Now we have to set up the model you want to connect for authentication. Let's prepare our model. I am using the User
model for the authentication.
We have to use the HasApiTokens
trait in the user model. Also, need to import the namespace Laravel\Passport\HasApiTokens
at the top. So here is our User
model.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
Now go to the config/auth.php
file and you will find the guard
array like this.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
Now we have to modify it and need to add another guard in the array named api
whose driver
should be passport
and whose provider
should be users
as we are using users as our authentication table. Now the guards
array should look like this.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
Now When deploying Passport to your application's servers for the first time, you will likely need to run the passport:keys
command. This command generates the encryption keys Passport needs in order to generate access tokens. The generated keys are not typically kept in source control:
php artisan passport:keys
Now, open AppServiceProvider
and add this code Passport::enablePasswordGrant();
to the boot method. And your AppServiceProvider
should look like this.
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Laravel\Passport\Passport;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Passport::enablePasswordGrant();
}
}
Now we need to create password grant client using this command
php artisan passport:client --password
It will generate a password secret id and a secret key. You need to add these code in your .env
file like this.
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:tq7VnODMFUn5CLAaaiXEy338CS9LxSr4RxPrvC+q1WA=
APP_DEBUG=true
APP_TIMEZONE=UTC
APP_URL=http://passport-authentication.test
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
APP_MAINTENANCE_STORE=database
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=passport_authentication
DB_USERNAME=root
DB_PASSWORD=
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=database
CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=log
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
PASSPORT_PASSWORD_CLIENT_ID=9c1a21e3-307b-473e-a325-bd14ac0fdbc2
PASSPORT_PASSWORD_SECRET=VuFvz2GNiwJrRQMyF9FZLg9r4vb0zYXwhQMYH4NJ
Look at the bottom of this .env
file. I have added two variables named PASSPORT_PASSWORD_CLIENT_ID
and PASSPORT_PASSWORD_SECRET
.
Now, we are ready to create our route and controller code. Now go to the routes/api.php
and create these routes. Here our routes should look like this.
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\AuthController;
Route::post('/login', [AuthController::class, 'login']);
Route::post('/register', [AuthController::class, 'register']);
Route::post('/refresh', [AuthController::class, 'refreshToken']);
Route::group(['middleware' => ['auth:api']], function () {
Route::get('/me', [AuthController::class, 'me']);
Route::post('/logout', [AuthController::class, 'logout']);
});
Now create a controller in Api
folder using following this command.
php artisan make:controller Api/AuthController
Now open the AuthController.php
and replace this code in this code.
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\LoginRequest;
use App\Http\Requests\RefreshTokenRequest;
use App\Http\Requests\RegisterRequest;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;
class AuthController extends Controller
{
/**
* User registration
*/
public function register(RegisterRequest $request): JsonResponse
{
$userData = $request->validated();
$userData['email_verified_at'] = now();
$user = User::create($userData);
$response = Http::post(env('APP_URL') . '/oauth/token', [
'grant_type' => 'password',
'client_id' => env('PASSPORT_PASSWORD_CLIENT_ID'),
'client_secret' => env('PASSPORT_PASSWORD_SECRET'),
'username' => $userData['email'],
'password' => $userData['password'],
'scope' => '',
]);
$user['token'] = $response->json();
return response()->json([
'success' => true,
'statusCode' => 201,
'message' => 'User has been registered successfully.',
'data' => $user,
], 201);
}
/**
* Login user
*/
public function login(LoginRequest $request): JsonResponse
{
if (Auth::attempt(['email' => $request->email, 'password' => $request->password])) {
$user = Auth::user();
$response = Http::post(env('APP_URL') . '/oauth/token', [
'grant_type' => 'password',
'client_id' => env('PASSPORT_PASSWORD_CLIENT_ID'),
'client_secret' => env('PASSPORT_PASSWORD_SECRET'),
'username' => $request->email,
'password' => $request->password,
'scope' => '',
]);
$user['token'] = $response->json();
return response()->json([
'success' => true,
'statusCode' => 200,
'message' => 'User has been logged successfully.',
'data' => $user,
], 200);
} else {
return response()->json([
'success' => true,
'statusCode' => 401,
'message' => 'Unauthorized.',
'errors' => 'Unauthorized',
], 401);
}
}
/**
* Login user
*
* @param LoginRequest $request
*/
public function me(): JsonResponse
{
$user = auth()->user();
return response()->json([
'success' => true,
'statusCode' => 200,
'message' => 'Authenticated use info.',
'data' => $user,
], 200);
}
/**
* refresh token
*
* @return void
*/
public function refreshToken(RefreshTokenRequest $request): JsonResponse
{
$response = Http::asForm()->post(env('APP_URL') . '/oauth/token', [
'grant_type' => 'refresh_token',
'refresh_token' => $request->refresh_token,
'client_id' => env('PASSPORT_PASSWORD_CLIENT_ID'),
'client_secret' => env('PASSPORT_PASSWORD_SECRET'),
'scope' => '',
]);
return response()->json([
'success' => true,
'statusCode' => 200,
'message' => 'Refreshed token.',
'data' => $response->json(),
], 200);
}
/**
* Logout
*/
public function logout(): JsonResponse
{
Auth::user()->tokens()->delete();
return response()->json([
'success' => true,
'statusCode' => 204,
'message' => 'Logged out successfully.',
], 204);
}
}
Now, create three request file step by step.
RegisterRequest:
php artisan make:request RegisterRequest
Now replace this code in this file.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class RegisterRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'name' => ['required', 'max:255'],
'email' => ['required', 'email', 'unique:users'],
'password' => ['required', 'min:8', 'confirmed'],
];
}
}
LoginRequest:
php artisan make:request LoginRequest
Now replace this code in this file.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class LoginRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'email' => 'email|required',
'password' => 'required',
];
}
}
RefreshTokenRequest:
php artisan make:request RefreshTokenRequest
Now replace this code in this file.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class RefreshTokenRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'refresh_token' => ['required', 'string'],
];
}
}
One more suggestion:
Sometimes you might need to change the refresh token and access token validity. For these changes you can add the following code in the boot method of AppServiceProvider
.
Passport::tokensExpireIn(now()->addDays(15));
Passport::refreshTokensExpireIn(now()->addDays(30));
Passport::personalAccessTokensExpireIn(now()->addMonths(6));
Then your AppServiceProvider
should look like this.
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Laravel\Passport\Passport;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Passport::tokensExpireIn(now()->addDays(15));
Passport::refreshTokensExpireIn(now()->addDays(30));
Passport::personalAccessTokensExpireIn(now()->addMonths(6));
Passport::enablePasswordGrant();
}
}
Congrats. You completed all the steps and HERE WE GO
. You are ready to test your API.
You will get all the code in this git repository for your help.
Top comments (8)
Nice content.
Thank you so much bhai <3
where is json token created
Cool
Thanks a lot <3
Working like charms!
its taking lots of time and throwing it exceeded the timelimit but its updating in my db.
how to fix this?
Password Grant is legacy. It is discouraged by Laravel:
laravel.com/docs/11.x/passport#pas...