Saturday, November 23, 2019

Integrate Passport to your Laravel API’s

Hello everyone, welcome back to justlaravel.com. I am back with another tutorial, here I will show you how to integrate Passport(a Laravel’s API authentication package) into your Laravel applications.
Here I will create 2 Laravel projects, one is an API and other is the API consumer app. It basically means I will create an API with Passport package integrated. A normal Laravel app where I call the API and show its data.
Let’s get started!
  • Laravel API

    • Passport Install

    • Passport Configure

    • Generate data – Faker | DB Seeding

    • Routing | Getting info from DB

    • Protect the routes with Passport

    • Registration and Generating OAuth client_id and client_secret

  • Consumer APP

    • Create a new App

    • Install GuzzleHttp

    • Authenticate the API and get the data

    • Display the data

    • Run the app

First, let us create an API. In the terminal/command prompt run the following command to create a new Laravel project.
laravel new sampleAPI

Passport Install

Now, install the Passport package using composer,
composer require laravel/passport
Now, register the Passport service provider in the providers array of your config/app.php file.
Now,  run the following commands to setup passport, but before that setup database details in .env file  ordatabase.php(app\config\database.php) file.
The migrate command creates some default Laravel tables and some new tables for authentication which comes from passport.
Now run,
it creates some client id’s and secrets, which can be later used by consumer app to access the API.

Passport Configure

Here we need to make some configuration changes to our Laravel app so Passport can be used in the API authentication.
Now, in the User model(app\User.php) we need to add HasApiTokens trait from Passport package,
Next, we need to add some routes which passport uses, so in the AuthServiceProvider<code>(</code>app/Providers/AuthServiceProvider.php) add the below extra lines,
And finally, in auth.php file(config/auth.php), I will set the API driver to passport.

Generate data – Faker | DB Seeding

As this is not a real API and just for tutorial purpose, I can stuff with some dummy data.
Now I will generate some random fake data so we can fill up the API with some data. We can use an inbuilt Laravel package Faker to get us some data.
I will now create a copy of users table and fill that table with dummy users. Create a  new details table by running the following SQL query.
Let’s create a seeder for details table, run the following command,
In the Seeder file(database\seeds\DetailsTableSeeder.php),  loop and create 250 random users, paste the following in  the run() function of the seeder.
Now, in the Database seeder file(database\seeds\DatabaseSeeder.php), call this DetailsTableSeeder
Now, we can run the migrate command which fills us the database.
1
php artisan migrate --seed


Routing | Getting info from DB

Now, lets create a route to the controller which gets all the user data, so in the api routes(\routes\api.php) place the following route.
Its time to create a new controller named DetailController as used in the above route.
In the controller(app\Http\Controllers\DetailController.php), lets create a function and fetch all the data from user table.
Now if we run the application(php artisan serve) and go to route(http://127.0.0.1:8000/api/users), it will display us all the users, but the thing here is everyone can see the details of the API, it just a normal app. An API needs authentication, so now let us use the passport package we have installed earlier.


Protect the routes with Passport

Let’s protect the route which we created earlier for displaying the users. Open api.php file(routes\api.php) and add middleware authentication to the route.
1
Route::get('users', 'UserController@index')->middleware('auth:api');
Now if we check the link(http://127.0.0.1:8000/api/users), we are now unable to access the data as it is protected with the passport and it needs some authentication.

Registration and Generating OAuth client_id and client_secret

So to access we need some client_id and client_secret, we have got some of these when I ran php artisan passport:install earlier and these are stored in a table called oauth_clients.
Now, if any user wants to access our API, we need them to register to the API and then generate those client_id and client_secret for them so they can access the API.
For registration view, I used the basic files generated that comes from Laravel’s auth scaffolding. So I ran, php artisan make:auth and removed all unnecessary files and kept only view files also removed its controllers and routes.
So make a new route in (routes\web.php) calling the registration view.
1
2
3
Route::get('/register', function(){
    return view('auth.register');
});
 

So when the registration form is submitted, a new user is created and also an OAuth client id and secret are generated for that user.
The route(routes/web.php),
In the register function, I first save the user and then get its id and use it in oauth_clients table. So as am dealing with one or more insertions for an operation, I use a concept called DB Transactions, what this does is, it either inserts in both of the tables or none of them. As I don’t need any sort of incomplete operations here.
Assume a case where the user is created and got an error in creating a record in oauth_clients table, in this case, there is a problem, so to avoid such situations there is a concept called Transactions and Atomicity property of the transaction is what we use here.
So the basic flow of operation looks like,
In the registration form, I check for some basic validations and then proceed to insert the user.
Now, in the else part, I will create a new user, enclosing with try catch block for rollback scenario.
After the user is created, I will get the inserted id to use it the oauth_clients table.
Now, there is some data to be inserted in oauth_clients table.
Secret – A random 40 character string
Name – Any name
Password Client – As it is password access client the value should be ‘1’
Personal Access Client – It should be 0 as it is a password client and not personal
Redirect – A redirect URL
Revoked  – whether the client revoked the access or not, it should be ‘0’ as we need access to the API
So the insert query for oauth_clients will look as follows,
After successful insertion of both queries, I can use DB commit and give the user the required client id and secret.
The final register function looks as below.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use DB;
use App\User;
use App\OAuthClient;
use Str;
use Validator;
use Redirect;
 
class PassportController extends Controller
{
    public function register(Request $request)
    {
        DB::beginTransaction();
 
        try {
            $validator = Validator::make($request->all(),[
            'name' => 'required|string',
            'email' => 'required|string|email|unique:users',
            'password' => 'required|string|confirmed'
            ]);
            
            if ($validator->fails()) {
                return Redirect::back()
                            ->withErrors($validator)
                            ->withInput();
            }
            else{
                try {
                    $user_save = User::create([
                        'name' => $request->name,
                        'email' => $request->email,
                        'password' => bcrypt($request->password)
                    ]);
                }
                catch(\Exception $e){
                    DB::rollback();
                    $message = $e->getMessage();
                    return response()->json(['error' => 1, 'message' => $message]);
                }
            }
            $insertedId = $user_save->id;
            $secret = Str::random(40);
            try {
                $oauth_clients = OAuthClient::create([
                    "user_id" => $insertedId,
                    "secret" => $secret,
                    "name" => "Password Grant",
                    "revoked" => 0,
                    "password_client" => 1,
                    "personal_access_client" => 0,
                    "redirect" => "http://localhost",
                ]);
            }
            catch(\Exception $e){
                DB::rollback();
                $message = $e->getMessage();
                return response()->json(['error' => 1, 'message' => $message]);
            }
            DB::commit();  
            return response()->json([
                'message' => 'Successfully created user!',
                'client_secret' => $secret,
                'client_id' => $oauth_clients->id
            ], 201);
        } catch (\Exception $e) {
            DB::rollback();
            // something went wrong
            $message = $e->getMessage();
            return response()->json(['error' => 1, 'message' => $message]);
        }
    }
}

Consumer App

Now, let us create a consumer app, where this API data is fetched and displayed.

Create a new App

Let us create a new Laravel app,

Install GuzzleHttp

Here I use GuzzleHttp package to call the API just created. So let us install it. In the consumerApp root, run the following command to install it,

Authenticate the API and get the data

Now, let us authenticate the API and get data from the API. Here it is only one function so I will manage everything in a single function in the routes file(routes\web.php)
Assuming the API we created is running at http://localhost:8000
I will call the url http://localhost:8000/oauth/token  with post method, this URL is one of the route created by the passport package.
As you see there are some form_params to be passed to it, client_id and client_secret are the one which obtained when registered to the API and the grant_type is password, and also we need to provide the username and password used for registering to the API, also scope should be passed as *
With the above call, we get an access_tokenand pass this access_token as a Header to the actual API call to get all the details.
Now, the obtained data is stored in some variable, so we can loop it and display the data accordingly.
1
$details = json_decode( (string) $response->getBody() );

Display the data

Here I will use a basic HTML table to display the data.

Run the app

So now lets run the application and see. As the API is running on default port 8000. Let us change the port and run it.
So now when we open http://localhost:8594/ we can see the data, which looks like the below image.
So that’s it, guys! We have successfully created an API with passport authentication and also consumed that API in another application.

Load disqus comments

0 comments