Laravel Passport is an easy way to set up an authentication system for your API. As a Laravel package, it uses an OAuth2 server to perform authentication, creating tokens for user applications that request to interface with the API it protects, and only granting them access if their tokens are validated.
In this article, we will build an API that interacts with our database and processes the data of employees. The API will be secured using Passport, which will allow access to certain protected information only when an access token is provided.
REST APIs have become the backbone of web platforms and data processing. This is because they encourage flexibility and scalability. With a REST API controlling the backend of an application, all kinds of client applications can interface with it, regardless of the language in which they are written. This way, a web app can service a wide variety of users.
One drawback of REST APIs is that they are stateless. In other words, application states are not kept on the server side. There are no sessions to keep track of states, like whether or not a user is logged in. One of the reasons for this is that asking the server to store the sessions of perhaps millions of users would overload it, thereby leading to performance bottlenecks and hindering scalability.
And so with REST APIs, it becomes the responsibility of the client application to store its own information and provide the server with all the information it needs every time a request is made. This constant state transfer is what the “ST” in “REST” stands for.
Rather than servers saving states and consuming lots of time and space, with REST APIs, client applications are provided with credentials to be sent to the server with each request. This credential is usually called an authorization token. The server validates this token, and then gives the client application access to the resources it requires. This process is called authentication.
Why is authentication important? APIs provide access to the information stored in your database – most likely sensitive information that you don’t necessarily want the general public to have access to. You need a way to verify that the user trying to access your information has permission. This is where authentication comes in.
By the end of this tutorial, you’ll have built a secure API that can be used to:
These are employee details to be saved in the database:
In order to follow along with this tutorial, you should have the following:
There are two ways to scaffold a new application in Laravel. To use the Laravel installer, run:
laravel new application-name
To use composer instead, run:
composer create-project --prefer-dist laravel/laravel application-name
If you want to check out the boilerplate that comes with a newly created Laravel project, navigate into the directory of the project you just created and run:
php artisan serve
Open your web browser and enter the following url: http://localhost:8000
Now that we have an app up and running, we need to hook it up with a database. Create a database for your app and add the appropriate values for the following variables in your .env
file:
DB_DATABASE
DB_USERNAME
DB_PASSWORD
With our database set up, we can proceed to setting up Passport in our application.
Passport implements OAuth2 authentication in our app. It generates a unique token for every authenticated user, so every request sent to the API to access protected routes will be accompanied by this token. To install Passport with Composer, run the following command:
composer require laravel/passport
Passport will need to store OAuth2 clients and access tokens in some database tables, so it creates migrations for the tables during installation. Migrate your database to create the tables:
php artisan migrate
To generate secure access tokens for your application, Passport requires some encryption keys and two clients known as Laravel Personal Access Client and Laravel Password Grant Client. To create these keys and encryption clients, run the following command:
php artisan passport:install
To access certain protected routes in our application, our users will need to register and login. Not to worry, new Laravel applications come with a User
model and users migration file out of the box. This will be sufficient for our needs.
You’ll need to inspect all authenticated users’ tokens and scopes. The HasApiTokens
trait will provide you with some helper methods to carry this out. To add it to your User
model, navigate to App\Models\User
, add its namespace at the top, and specify for it to be used inside the User
class:
<?php namespace App\Models; ... use Laravel\Passport\HasApiTokens; //add the namespace class User extends Authenticatable { use HasApiTokens, HasFactory, Notifiable; //use it here }
Passport comes with some routes used to issue and revoke access tokens. To register these routes, you need to call the Passport::routes
method inside the boot method in your AuthServiceProvider
. Navigate to App\Providers\AuthServiceProvider
and update it.
In Laravel, Policies
are used to protect resources from unauthorized access. Since some of our routes will need to be protected and will require access tokens to be accessed, we’ll be making use of Policies
.
Inside the $policies
array, comment this line: 'App\Models\Model' => 'App\Policies\ModelPolicy'
to make it available for use:
<?php namespace App\Providers; use Laravel\Passport\Passport; //import Passport here class AuthServiceProvider extends ServiceProvider { /** * The policy mappings for the application. * * @var array */ protected $policies = [ 'App\Models\Model' => 'App\Policies\ModelPolicy', //uncomment ]; /** * Register any authentication / authorization services. * * @return void */ public function boot() { $this->registerPolicies(); Passport::routes(); //Register Passport routes // } }
Your application needs to use Passport’s TokenGuard
to authenticate incoming API requests. To set this up, navigate to your config/auth.php
file, go to your api
authentication guard, and set the value of the driver
option to passport
:
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'passport', //update this line 'provider' => 'users', ], ],
To create a database to store our employees’ information, we’ll be creating an employee model and a migrations file using the below artisan command:
php artisan make:model Employee -m
The make:model
command will create the new model inside your app
folder. The -m
flag will create the new migrations file inside your database/migrations
folder.
Now, let’s proceed to creating our employees’ database table. Navigate to database/migrations
, open your newly created create_employees_table
file, and add the appropriate columns for all the employee information we’ll be storing (name, age, job, and salary):
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateEmployeesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('employees', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('age'); $table->string('job'); $table->string('salary'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('employees'); } }
Next, let’s align our Employee
model with our migrations file above:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Employee extends Model { protected $fillable = [ 'name', 'age', 'job', 'salary' ]; }
To create the table for which we just created the migrations file above, run the command below:
php artisan migrate
If you check your database now, you should see the employees table with all the fields we specified.
Before we create the controller that will handle employees details, let’s create the controller that will enable users be able to register, login, and use our application.
Use the command below to create it (we’ll call it UserAuthController
and create a new folder for it called Auth
):
php artisan make:controller Auth/UserAuthController
You can find the newly created controller in app/Http/Controllers/Auth
. Let’s proceed to creating the register and login methods we need:
<?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Models\User; use Illuminate\Http\Request; class UserAuthController extends Controller { public function register(Request $request) { $data = $request->validate([ 'name' => 'required|max:255', 'email' => 'required|email|unique:users', 'password' => 'required|confirmed' ]); $data['password'] = bcrypt($request->password); $user = User::create($data); $token = $user->createToken('API Token')->accessToken; return response([ 'user' => $user, 'token' => $token]); } public function login(Request $request) { $data = $request->validate([ 'email' => 'email|required', 'password' => 'required' ]); if (!auth()->attempt($data)) { return response(['error_message' => 'Incorrect Details. Please try again']); } $token = auth()->user()->createToken('API Token')->accessToken; return response(['user' => auth()->user(), 'token' => $token]); } }
We now have a register method to create new users for our application.
Using Laravel’s validate()
method, we ensure that the name field is filled and that the value entered into it does not exceed 255 characters. We also ensure that an email is entered for registration and that it is unique.
We use Laravel’s bcrypt
function to hash the user’s password, as it is not safe to store their password as plain text. If all the registration requirements we’ve set are met, a new user account is created, an access token is generated, and the new user’s details, along with their user token, are returned back as response.
For the login method, we use Laravel’s validate()
method again to ensure that both an email and a password are supplied. The auth()→attempt()
method tries to login the user with the details they’ve provided. If the details are not the same as the ones with which they registered, an error message is displayed, asking them to try again. If the details are correct, an access token is created and the user is logged in – now ready to access our protected routes.
To access any protected route, the access token that was created will have to be passed along with the HTTP request, signaling to our application that the user is authorized to access private resources.
The controller that will process employee data will be returning responses in JSON format. Since we’ll mostly be returning model instances and collections of model instances, we can use Laravel Eloquent’s API Resources. If a user requests a list of employees, we can use resource
to send the employee model back as response, in JSON format. If a user requests for the details of an employee, we can use resource
to send that particular model instance back.
So let’s go ahead and create a Resource
file for our Employee
model:
php artisan make:resource EmployeeResource
Now if we need to send out employees details as response to an API call, we can use EmployeeResource
to send them out in JSON format (in the form of an array). The advantage of this is that all kinds of client applications (Flutter, Angular, React etc.) can process JSON data easily.
The incoming HTTP requests our app will receive are going to be processed by a controller we will call the employee controller. The methods in this controller will return the appropriate responses to the HTTP requests in JSON format:
php artisan make:controller EmployeeController --api --model=Employee
The --api
flag helps us create the five methods that are commonly used to perform operations on resources: index, store, show, update, and destroy. The --model
flag signifies that the controller we are creating is for the Employee
model and lets us use route model binding in the controller.
Now that we have a controller, let’s start creating the methods we need to process employee data. Navigate to your newly created controller app/Http/Controllers/EmployeeController.php
and open it:
?php namespace App\Http\Controllers; use App\Models\Employee; use App\Http\Controllers\Controller; use App\Http\Resources\EmployeeResource; use Illuminate\Http\Request; use Illuminate\Support\Facades\Validator; class EmployeeController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { $employees = Employee::all(); return response([ 'employees' => EmployeeResource::collection($employees), 'message' => 'Successful'], 200); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $data = $request->all(); $validator = Validator::make($data, [ 'name' => 'required|max:50', 'age' => 'required|max:50', 'job' => 'required|max:50', 'salary' => 'required|max:50' ]); if($validator->fails()){ return response(['error' => $validator->errors(), 'Validation Error']); } $employee = Employee::create($data); return response([ 'employee' => new EmployeeResource($employee), 'message' => 'Success'], 200); } /** * Display the specified resource. * * @param \App\Employee $employee * @return \Illuminate\Http\Response */ public function show(Employee $employee) { return response([ 'employee' => new EmployeeResource($employee), 'message' => 'Success'], 200); } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param \App\Employee $employee * @return \Illuminate\Http\Response */ public function update(Request $request, Employee $employee) { $employee->update($request->all()); return response([ 'employee' => new EmployeeResource($employee), 'message' => 'Success'], 200); } /** * Remove the specified resource from storage. * * @param \App\Employee $employee * @return \Illuminate\Http\Response * @throws \Exception */ public function destroy(Employee $employee) { $employee->delete(); return response(['message' => 'Employee deleted']); } }
The index
method above gets the details of all the employees in our database and returns it in JSON format, using Resources
. We use the store
method to add the details of a new employee to the database. Using Laravel’s Validator, we ensure that information for all the columns in our employee table are provided. Then we return the details of the new employee in JSON format.
The show
method fetches the details of a particular employee and returns it as JSON response. Here, we do not need to write code to query the database with a particular employee ID because we are making use of route model binding.
The update
method is sent new information for an existing employee. It then updates the employee’s record in the database with this new information and returns the information back as response in JSON format. Just like with the show
method, we do not need to write code to query the database with a particular employee ID, as we are making use of route model binding. It’s done automatically.
The destroy
method simply deletes the details of an existing employee from the database and returns a success message.
Next, let’s create the routes (endpoints) that will be responsible for responding to HTTP requests and redirecting them to the appropriate methods to process them and return a response. Navigate to routes/api.php
and update it:
Route::post('/register', 'Auth\UserAuthController@register'); Route::post('/login', 'Auth\UserAuthController@login'); Route::apiResource('/employee', 'EmployeeController')->middleware('auth:api');
The first route above points to the register method we created inside our UserAuthController
. Now, when this endpoint is called, our register
method is triggered and a new user is created. The second route points to our login
method, which is for logging in users.
The third route points to all the methods that will be responsible for processing employees’ data. Since our application is an API that simply provides endpoints to be called, we do not need routes and methods for HTML templates, like create
and edit
. By using the apiResource
method above, we can exclude these two routes automatically and only create routes like index, store, show, update, and destroy. These 5 routes are represented by the apiResource
method and they are pointing to the corresponding 5 methods in the Employee
controller we created above.
We’ve used Passport to secure these routes by adding the auth:api
middleware to them. Now, a valid access token will be required for any call made to any of these routes.
And we are done! To test your application, run the following command:
php artisan serve
I’ll be using Postman to test my API endpoints. You can use any software you are comfortable with.
Our end point for creating a new user is http://localhost:8000/api/register. Using a POST request, supply a name, email, and password as shown below.
Now we can login the user we just created using this endpoint: http://localhost:8000/api/login.
We can add a new employee to our database by sending their name, age, job, and salary to this endpoint: http://localhost:8000/api/employee.
Since this is a protected endpoint, be sure to copy the access token you were provided with when you logged in, click on the authorization tab in Postman, select Bearer Token on the Type dropdown list, and paste your token inside the Token field.
You can get the list of employees from your database by using this endpoint: http://localhost:8000/api/employee. This time, we use a GET request.
To get the details of a particular employee, we use the following endpoint: http://localhost:8000/api/employee/1. Here, “1” should be changed to the particular ID of the employee.
To update the details of an employee, fill in the new details and send a PATCH request to http://localhost:8000/api/employee/1 (be sure to use the appropriate ID).
To delete the details of an employee, send a DELETE request to http://localhost:8000/api/employee/1 (be sure to use the appropriate ID).
In 5 steps, we’ve created a REST API and secured it with Laravel Passport. To find out more about how to use Passport, you can check out the official documentation here. There’s also a Github repository for the project we built in this tutorial, in case you need it.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]
5 Replies to "Laravel Passport: A tutorial and example build"
I had to prepend the path to the controller in the api.php file with App\Http\Controllers\ to get it working. Otherwise I got “Target class [Auth\UserAuthController] does not exist.”
Plus the code block for the EmployeeController misses a “<" at the beginning.
‘salary’ => ‘required|50’ should be ‘salary’ => ‘required|max:50’, otherwise will through a validation method error.
Hi N’chaka – Thanks for the catch, the typo has been fixed.
“The GET method is not supported for route api/login. supported methods:post”. I don’t get this error help me to fix this..
Great