Create REST API in Laravel with authentication using Passport

Ugur Ozyilmazel
Ugur Ozyilmazel 10 June 2021
Author:

The concept of authentication has a very important place in application development processes. Different programming languages contain different solutions and approaches in themselves. In this article, while developing Rest API with Laravel Framework, we will authenticate with Laravel Passport, the official package of Laravel.

What is Laravel

Laravel is a PHP framework used for developing web applications. Laravel includes many advanced features and has many useful features of PHP and OOP. Laravel's motto, which is used by a wide audience, is: "Web Artists' PHP Framework". You can access the official document from this link: https://laravel.com/.

Why Laravel

It is preferred by many developers because it keeps pace with the rapid change of Software Technology and offers us software principles and saves us from most of the manual work (Authentication, Middleware, ORM, MVC) that is required for project development to make it fast, reliable and testable.

What is Laravel Passport

It is the official Laravel package that facilitates authentication in Rest APIs and is written with Laravel.

Creating a Boilerplate Application

In this section, we will develop a Rest API application in Laravel step by step and look at the use of Passport.

Install Laravel

First of all, we install Laravel Framework on our computer via Composer. If you do not have Composer on your computer, you can download it from this link (https://getcomposer.org/).

    
composer create-project --prefer-dist laravel/laravel blog
    

Install Passport

We will install Passport on our computer through Composer. Then we will perform the default setup of the database and tokens with the last two commands.

    
composer require laravel/passport

php artisan migrate
php artisan passport:install
    

Configure Passport

In this step, we will set up Passport settings. We create three different php extension files and paste the following codes.

File: app/User.php

    
        // app/User.php 

        namespace App;
        use Illuminate\Notifications\Notifiable;
        use Illuminate\Contracts\Auth\MustVerifyEmail;
        use Laravel\Passport\HasApiTokens;
        use Illuminate\Foundation\Auth\User as Authenticatable;
        
        class User extends Authenticatable implements MustVerifyEmail
        {
            use HasApiTokens, Notifiable;
            /**
             * The attributes that are mass assignable.
             *
             * @var array
             */
            protected $fillable = [
                'name', 'email', 'password',
            ];
        
            /**
             * The attributes that should be hidden for arrays.
             *
             * @var array
             */
            protected $hidden = [
                'password', 'remember_token',
            ];
        }
    

File: app/Providers/AuthServiceProvider.php

    
        // app/Providers/AuthServiceProvider.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();
            }
        }
    

File: config/auth.php

    
        // config/auth.php
        return [
            // .... 
            'guards' => [
                'web' => [
                    'driver' => 'session',

                    'provider' => 'users',
                ],
                'api' => [
                    'driver' => 'passport',
                    'provider' => 'users',
                ],
            ],
            // .... 
        ]

    

Add Product Table and Model

First, we run the following command to perform the database migration process.

    
        php artisan make:migration create_products_table
    

After running this command, a file named "database / migrations" will be created in the project directory. Paste the codes below into this file

    
        use Illuminate\Support\Facades\Schema;
        use Illuminate\Database\Schema\Blueprint;
        use Illuminate\Database\Migrations\Migration;

        class CreateProductsTable extends Migration
        {
            /**
            * Run the migrations.
            *
            * @return void
            */
            public function up()
            {
                Schema::create('products', function (Blueprint $table) {
                    $table->bigIncrements('id');
                    $table->string('name');
                    $table->text('detail');
                    $table->timestamps();
                });
            }

            /**
            * Reverse the migrations.
            *
            * @return void
            */
            public function down()
            {
                Schema::dropIfExists('products');
            }
        }
    

After creating migration, we run the following command.

    
        php artisan migrate
    

We created the "Product" table and now we will create our product model. We create a file named "Product.php" in the project directory and paste the following codes.

File: app/Product.php

    
        // app/Product.php
        namespace App;
        use Illuminate\Database\Eloquent\Model;
        class Product extends Model
        {
            /**
             * The attributes that are mass assignable.
             *
             * @var array
             */
            protected $fillable = [
                'name', 'detail'
            ];
        }
    

Create API Routes

In this step, we will create api routes. Laravel provides an api.php file for writing web services routes. So, let's add a new route on that file.

File: routes/api.php

    
        // routes/api.php
        /*
        |--------------------------------------------------------------------------
        | API Routes
        |--------------------------------------------------------------------------
        |
        | Here is where you can register API routes for your application. These
        | routes are loaded by the RouteServiceProvider within a group which
        | is assigned the "api" middleware group. Enjoy building your API!
        |
        */
        Route::post('register', 'API\[email protected]');
        Route::post('login', 'API\[email protected]');
        Route::middleware('auth:api')->group( function () {
            Route::resource('products', 'API\ProductController');
        });
    

Create Controller Files

In this step, we will create three Controllers as BaseController, ProductController and RegisterController, where we will create our Rest APIs. Paste the codes below.

File: app/Http/Controllers/API/BaseController.php

    
        // app/Http/Controllers/API/BaseController.php
        namespace App\Http\Controllers\API;
        use Illuminate\Http\Request;
        use App\Http\Controllers\Controller as Controller;

        class BaseController extends Controller
        {
            /**
            * success response method.
            *
            * @return \Illuminate\Http\Response
            */

            public function sendResponse($result, $message)
            {
                $response = [
                    'success' => true,
                    'data'    => $result,
                    'message' => $message,
                ];
                return response()->json($response, 200);
            }

            /**
            * return error response.
            *
            * @return \Illuminate\Http\Response
            */

            public function sendError($error, $errorMessages = [], $code = 404)
            {
                $response = [
                    'success' => false,
                    'message' => $error,
                ];

                if(!empty($errorMessages)){
                    $response['data'] = $errorMessages;
                }
                return response()->json($response, $code);
            }
        }
    

File: app/Http/Controllers/API/RegisterController.php

    
        // app/Http/Controllers/API/RegisterController.php
        namespace App\Http\Controllers\API;

        use Illuminate\Http\Request;
        use App\Http\Controllers\API\BaseController as BaseController;
        use App\User;
        use Illuminate\Support\Facades\Auth;
        use Validator;

        class RegisterController extends BaseController
        {
            /**
            * Register api
            *
            * @return \Illuminate\Http\Response
            */
            public function register(Request $request)
            {
                $validator = Validator::make($request->all(), [
                    'name' => 'required',
                    'email' => 'required|email',
                    'password' => 'required',
                    'c_password' => 'required|same:password',
                ]);

                if($validator->fails()){
                    return $this->sendError('Validation Error.', $validator->errors());       
                }

                $input = $request->all();
                $input['password'] = bcrypt($input['password']);
                $user = User::create($input);
                $success['token'] =  $user->createToken('MyApp')->accessToken;
                $success['name'] =  $user->name;

                return $this->sendResponse($success, 'User register successfully.');
            }

            /**
            * Login api
            *
            * @return \Illuminate\Http\Response
            */
            public function login(Request $request)
            {
                if(Auth::attempt(['email' => $request->email, 'password' => $request->password])){ 
                    $user = Auth::user(); 
                    $success['token'] =  $user->createToken('MyApp')-> accessToken; 
                    $success['name'] =  $user->name;

                    return $this->sendResponse($success, 'User login successfully.');
                } 
                else{ 
                    return $this->sendError('Unauthorised.', ['error'=>'Unauthorised']);
                } 
            }
        }
    

File: app/Http/Controllers/API/ProductController.php

    
        // app/Http/Controllers/API/ProductController.php
        namespace App\Http\Controllers\API;
        use Illuminate\Http\Request;
        use App\Http\Controllers\API\BaseController as BaseController;
        use App\Product;
        use Validator;
        use App\Http\Resources\Product as ProductResource;

        class ProductController extends BaseController
        {
            /**
            * Display a listing of the resource.
            *
            * @return \Illuminate\Http\Response
            */
            public function index()
            {
                $products = Product::all();

                return $this->sendResponse(ProductResource::collection($products), 'Products retrieved successfully.');
            }

            /**
            * Store a newly created resource in storage.
            *
            * @param  \Illuminate\Http\Request  $request
            * @return \Illuminate\Http\Response
            */
            public function store(Request $request)
            {
                $input = $request->all();

                $validator = Validator::make($input, [
                    'name' => 'required',
                    'detail' => 'required'
                ]);

                if($validator->fails()){
                    return $this->sendError('Validation Error.', $validator->errors());       
                }

                $product = Product::create($input);

                return $this->sendResponse(new ProductResource($product), 'Product created successfully.');
            } 

            /**
            * Display the specified resource.
            *
            * @param  int  $id
            * @return \Illuminate\Http\Response
            */

            public function show($id)
            {
                $product = Product::find($id);
                if (is_null($product)) {
                    return $this->sendError('Product not found.');
                }

                return $this->sendResponse(new ProductResource($product), 'Product retrieved successfully.');
            }

            /**
            * Update the specified resource in storage.
            *
            * @param  \Illuminate\Http\Request  $request
            * @param  int  $id
            * @return \Illuminate\Http\Response
            */

            public function update(Request $request, Product $product)
            {
                $input = $request->all();

                $validator = Validator::make($input, [
                    'name' => 'required',
                    'detail' => 'required'
                ]);

                if($validator->fails()){
                    return $this->sendError('Validation Error.', $validator->errors());       
                }

                $product->name = $input['name'];
                $product->detail = $input['detail'];
                $product->save();

                return $this->sendResponse(new ProductResource($product), 'Product updated successfully.');
            }

            /**
            * Remove the specified resource from storage.
            *
            * @param  int  $id
            * @return \Illuminate\Http\Response
            */
            public function destroy(Product $product)
            {
                $product->delete();
                return $this->sendResponse([], 'Product deleted successfully.');
            }
        }
    

Create Eloquent API Resources

Eloquent API will help us to make the same response layout of your model object. We used it in the ProductController file.

    
        php artisan make:resource Product
    

Now there is the created new file with new folder on following path:

File: app/Http/Resources/Product.php

    
        //app/Http/Resources/Product.php

        namespace App\Http\Resources;
        use Illuminate\Http\Resources\Json\JsonResource;
        class Product extends JsonResource
        {
            /**
            * Transform the resource into an array.
            *
            * @param  \Illuminate\Http\Request  $request
            * @return array
            */
            public function toArray($request)
            {
                return [
                    'id' => $this->id,
                    'name' => $this->name,
                    'detail' => $this->detail,
                    'created_at' => $this->created_at->format('d/m/Y'),
                    'updated_at' => $this->updated_at->format('d/m/Y'),
                ];
            }
        }
    

Test Application

To test our application, we will first run it in a local environment with the command below. Then we will test our Restful APIs through Postman.

    
php artisan serve
    

After running the application, we perform our tests with Postman. You can view the screenshots.

Register API: Verb:GET, URL:http://localhost:8000/api/register

postman register endpoint

Login API: Verb:GET, URL:http://localhost:8000/api/login

postman login endpoint

Product Create API: Verb:POST, URL:http://localhost:8000/api/products

postman products endpoint

Product Show API: Verb:GET, URL:http://localhost:8000/api/products/{id}

postman product endpoint

Conclusion

In this article, we made our Rest APIs more secure by using Passport with Laravel very quickly with the speed factor, which is the biggest feature that Laravel provides to developers. Hope this information will be useful.

Share:
 
Ugur Ozyilmazel
Written by

Ugur Ozyilmazel

30+ years of experienced software developer