In today’s web development, APIs or web services are very popular. While developing a mobile application, API plays the role of bridge to passing data between mobile applications and the web. Keeping APIs call safe and authenticated is important to protect the data being transferred from application to application.
In this article, we study Laravel Passport which allows us to authenticate APIs. Passport is built on the top of the OAuth2 server which is much more secure in the way it builds.
When dealing with the APIs, we used to send an access token to verify if the incoming request is valid. If it is authorized then only it should allow interaction with the application. Laravel Passport provides a convenient way to create and verify tokens against the API call.
Installation
For getting started, we assume you have installed Laravel on your system. To install the Passport, run the below command in the terminal.
composer require laravel/passport
Above command would work with the latest version of Laravel. If you are running an older version then the command will be slightly different depending on your Laravel version. For instance, if have Laravel 5.5 installed then your command should be:
composer require laravel/passport=~4.0
This command creates its own database migrations directory. These migrations will create tables that store the clients and access tokens.
In your config/app.php
file, register the Passport service provider in the providers
array.
config/app.php
'providers' =>[
....
Laravel\Passport\PassportServiceProvider::class,
],
Let’s run the migration which will create the database tables for Passport.
php artisan migrate
Now, if you go to your database client, you will notice the new tables created in your database.
Next, run the below command which creates encryption keys to generate secure access tokens. The below command creates “personal access” and “password grant” clients which are getting stored in the table oauth_clients
.
php artisan passport:install
The user can copy these tokens for the next steps. Actually, we are going to see 2 ways of creating access tokens. One is through this “password grant” clients and another is on login authentication.
Passport Configuration
Head over to the Laravel directories and open App\User
model file. In this file, we need to add Laravel\Passport\HasApiTokens
trait.
app/User.php.
<?php
namespace App;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
....
}
After this, we have to call Passport::routes
method in the boot
method of AuthServiceProvider
.
app/Providers/AuthServiceProvider.php
<?php
namespace App\Providers;
use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Passport::routes();
}
}
At last, in the config/auth.php
file set the ‘driver’ option of ‘api’ authentication guard to ‘passport’ as follows:
config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
Create REST API and Protect it with Laravel Passport
Laravel creates a file routes/api.php
where we should declare our REST APIs endpoint. We can protect our API by adding the middleware auth:api
to it.
routes/api.php
Route::get('/api/categories', 'ApiController@categories')->middleware('auth:api');
For multiple endpoints, we don’t need to add middleware each time. Instead, we can do it as follows:
Route::group(['middleware' => 'auth:api'], function(){
Route::get('products', 'ApiController@products');
Route::get('categories', 'ApiController@categories');
});
As our endpoint ‘products’ is protected if we call it directly without an Authorization token we get an ‘Unauthenticated’ response.
It means while calling API it is essential to pass the Authorization token in each request. So, Passport will verify the token and returns the response.
Generate Access Token for API
There are several ways to create an access token for the application. We will see 2 of them for this tutorial.
First Option
In the first option, you have to give a call to the /oauth/token with the required parameters and you will get the token in response.
We assume you are using a Guzzle HTTP library for making API requests. Let’s say you have another project from where you are making API requests.
<?php
require_once "vendor/autoload.php";
use GuzzleHttp\Client;
$client = new Client([
// Base URI is used with relative requests
'base_uri' => 'http://laravel.dev',
]);
$response = $client->post('/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => '2',
'client_secret' => '8qyKG7WKb3O3FZh2hUyEOZ3dAj5l9S5ljn2bdeJf',
'username' => 'sajid@test.com',
'password' => 'my_password',
'scope' => '*',
],
]);
$arr_result = json_decode((string) $response->getBody(), true);
The above code returns an array that contains a key ‘access_token’. The parameters client_id and client_secret we got when we run passport:install
. You can also get these details from your database table ‘oauth_clients’.
Again try from Postman by passing the access_token to the ‘products’ endpoint and we should get the response.
Actually you need to call this API like the below:
$response = $client->get('/products', [
'headers' => [
'Authorization' => 'Bearer '.$access_token,
]
]);
$arr_result = json_decode((string) $response->getBody(), true);
Second Option
In the first option, you should know the client_id and client_secret to generate your token. This may be not a convenient way in some scenarios. Passport provides another option to generate access tokens through login credentials only.
In our ApiController.php
add the login method with the post request and write the below code in it.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Auth;
class ApiController extends Controller
{
public function login(){
if(Auth::attempt(['email' => request('email'), 'password' => request('password')])){
$user = Auth::user();
$success['token'] = $user->createToken('MyApp')-> accessToken;
return response()->json(['success' => $success], 200);
}
else{
return response()->json(['error'=>'Unauthorised'], 401);
}
}
For making this API call, we need to register a route for it.
routes/api.php
Route::post('login', 'ApiController@login');
Users can make HTTP post requests to this API by writing the code below:
$response = $client->post('/api/login', [
'form_params' => [
'email' => 'sajid@test.com',
'password' => 'my_password'
],
]);
$arr_result = json_decode((string) $response->getBody(), true);
We hope you understand the use of Laravel Passport for REST API Authentication. We would like to hear your thoughts in the comment section below. We also recommend going through the article Laravel API Tutorial: How to Build and Test a RESTful API which we found useful for readers.
If you liked this article, then please subscribe to our YouTube Channel for video tutorials.
hello guys my question is where should i put the guzzle http defined function for it to authenticate all my requests
Thank you very much is very helpful, however I hope you can tell me how you could add the verification by mail using passport
Why do you want to use a passport to verify email? Laravel comes with built-in support for the verification email. Have a look at this article https://artisansweb.net/user-registration-login-system-laravel/
Please, How do I verify the new account using mail with Passport?
User can make HTTP post request to this API by writing the code below:
$response = $client->post(‘/api/login’, [
‘form_params’ => [
’email’ => ‘sajid@test.com’,
‘password’ => ‘my_password’
],
]);
$arr_result = json_decode((string) $response->getBody(), true);
Where is this code supposed to go?
why is the first option is bad for certain scenario? Could you elaborate more
In the first option, we need to know client id and clint secret while in the second option we just need to pass our email and password.