Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (1 vote)
28 views

How To Create A Secure CRUD RESTful API in Laravel 8 and 7 Using Laravel Passport - DEV Community

Secure

Uploaded by

Antonius Ajalah
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (1 vote)
28 views

How To Create A Secure CRUD RESTful API in Laravel 8 and 7 Using Laravel Passport - DEV Community

Secure

Uploaded by

Antonius Ajalah
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

Kingsconsult

Posted on Oct 15, 2020 • Updated on Mar 2, 2021

54 12

How to Create a Secure CRUD RESTful API in


Laravel 8 and 7 Using Laravel Passport
#php #laravel #webdev #beginners

Creating and Consuming API (2 Part Series)

1 How to Create a Secure CRUD RESTful API in Laravel 8 and 7 Us…

2 How to consume RESTful APIs in Laravel 8 and Laravel 7

Good day, today we are going to be coding strictly in the backend, we are going to
convert our Laravel 8 CRUD app to RESTful APIs. API is a software intermediary that
allows two applications to talk to each other. Somethings you might need to create
an app that can be run on different languages or frameworks, for example, you can
use Laravel to create the backend for your application while the frontend might run
on any JavaScript frameworks. API allows two or more programs to communicate
with each other.
There are different types of APIs, but today we are going to concentrate on RESTful
APIs. REST stands for Representational State Transfer, while API stands for
Application Programming Interface. You can read more about API from the internet
or other programming material.

Click on my profile to follow me to get more updates.

Normally, when we build an application, we need to secure the application so that


unauthorized access will be blocked. Laravel already makes it easy to perform
authentication via traditional login forms, but what about APIs? API does not
maintain a session state between requests, so there is a need to use tokens to
authenticate the app and also authorize the usage of the app.
Laravel provided a package that makes authentication of API very easy by using
Laravel Passport, though, there are other options, this is the official packages by the
Laravel team, this package provides a full OAuth2 server implementation. It is easy to
apply and can be achieved in minutes. Without saying much, let's dive into it.

STEP 1: install laravel 8


To install the latest laravel framework, which is laravel 8.0 as of the time of
publishing this article, run the command below

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

This will automatically create a laravel 8 app and some couple of things have been
set up, we don’t need to copy and rename the env.example file, Laravel 8 does that
automatically for us

Another important thing about Laravel 8, you don’t need to generate APP_KEY, this
new version will also generate it for us.

With that all set up, our app is ready.

Step 2: Database setup


Create an empty database, Open the .env file, and update your database
configurations.
For more information on this step, you can visit my previous article, where I explained
the steps very well, Laravel 8 CRUD.

Step 3: Install Laravel Passport


let us install Laravel Passport, Passport service provider registers its own database
migration directory, this means that it creates the table that we will be needing for
storing clients. The table will be used to store the token generated which will be used
to identify a currently authenticated user. This token will then be attached to every
request allowing each user access to protected routes.

composer require laravel/passport

After installation, then we need to migrate, but before we run our migration
command, we need to specify the default string length, else, we are going to run into
errors. So go to app/Providers/AppServiceProvider.php and add this to the boot
function
Schema::defaultstringLength(191);

also, add this to the top of the class

use Illuminate\Support\Facades\Schema;

Finally, we run our migration command

php artisan migrate


Step 4: Create the encryption keys
We need to create the encryption keys that are needed to generate our secure access
tokens.

php artisan passport:install

This command will also create "personal access" and "password grant" clients which
will be used to generate access tokens.

Step 5: Add the HasApiTokens trait to our user model


Go to App\Models\User.php and tell the User class to

use HasApiTokens,

Also add this to the top


use Laravel\Passport\HasApiTokens;

Step 6: Call the passport routes in AuthServiceProvider


Go to App/Providers/AuthServiceProvider.php and add

Passport::routes();

To the boot method, also add the path before the class at the top

use Laravel\Passport\Passport;

Uncomment the policy in the protected method of $policies


Step 7: Set the driver
This will be the final step in the setting up and configuration of Laravel\Passport, we
going to change our api driver from the default token to passport.
Go to config\auth.php and locate the guards array. In the api key, change the driver
from token to passport
Step 8: Create the Migration file for our CRUD api project
php artisan make:model Project -m

A migration file will be created in the database/migrations folder, and we need to


create our schema, I added name (string), introduction (string), location (string), cost
of the project (integer).

<?php

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

class CreateProjectsTable extends Migration


{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('projects', function (Blueprint $table) {
$table->id();
$table->string('name', 255);
$table->string('introduction', 500)->nullable();
$table->string('location', 255)->nullable();
$table->integer('cost')->nullable();
$table->timestamps();
});
}

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

We need to update our Project Model so that it can be able to accept the fields. We
need to add a protected $fillable method that will contain the fields that a user of the
app can fill, this helps to prevent someone from hacking into the app through input
fields.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Project extends Model


{
use HasFactory;

/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'location',
'introduction',
'cost',
];

/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'cost' => 'int',
];
}

Step 9: Migrate the new table

Step 10: Create a Resource


When building an API, the response will always be in JSON format, so we need a
transformation layer that sits between our Eloquent models and the JSON
responses. This is what will serve the response to the application’s user in a JSON
format. Laravel provides us with a resource class that will help in transforming our
models and the model collections into JSON. So we are going to create that

php artisan make:resource ProjectResource

This will create a folder in the app directory called Resources and also a file
ProjectResource.php inside the resources.
Step 11: Create our Controllers
The Controller is responsible for the direction of the flow of data and an interface
between the user and the database and views. In this case, we are not interacting
with views now because we are dealing with API, so our response will be in JSON
format. The standard for RESTful APIs is to send the response in JSON.
We are going to be creating two controllers, the first will be the Authentication
Controller and the second is our Project Controller, we need the Authentication
Controller in order to generate the token to use in Project Controller.

php artisan make:controller API/AuthController

This will create a folder called API in App/Http/Controllers. It will also create a new
file called AuthController.php. Click on AuthController.php and update it with the
following code.

<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Hash;

class AuthController extends Controller


{
public function register(Request $request)
{
$validatedData = $request->validate([
'name' => 'required|max:55',
'email' => 'email|required|unique:users',
'password' => 'required|confirmed'
]);

$validatedData['password'] = Hash::make($request->password);

$user = User::create($validatedData);

$accessToken = $user->createToken('authToken')->accessToken;

return response(['user' => $user, 'access_token' => $accessToken], 2


}

public function login(Request $request)


{
$loginData = $request->validate([
'email' => 'email|required',
'password' => 'required'
]);

if (!auth()->attempt($loginData)) {
return response(['message' => 'This User does not exist, check y
}

$accessToken = auth()->user()->createToken('authToken')->accessToken

return response(['user' => auth()->user(), 'access_token' => $access


}
}

In our AuthController, we created two methods: register and logic methods


In the register method, we use the Laravel Validate method to make sure that the
name, email, and password is provided, this will also make sure that the email has
not been taken and is a valid email address, the password must be confirmed before
the user will be added.
After the validation, we use hash to encrypt the password before creating the user,
we can't store plain password, lastly, we grab the access token and return it with the
user’s information.
In the login method, we also validate the data been pass, to make sure the email and
password are submitted, if the data did not correspond to any user, it will return a
message that the user does not exist, if it corresponds, then it returns the user and
the access token.

Let us create our ProjectController in the API using --api switch.

php artisan make:controller API/ProjectController --api --model=Project

The --api switch will create our Controller without the create and edit methods, those
methods will present HTML templates.
Go to App/Http/Controller/API, and click on ProjectController, copy the code below
and update the methods.

<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Models\Project;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\Http\Resources\ProjectResource;

class ProjectController extends Controller


{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$projects = Project::all();
return response([ 'projects' => ProjectResource::collection($project
}

/**
* 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:255',
'description' => 'required|max:255',
'cost' => 'required'
]);

if ($validator->fails()) {
return response(['error' => $validator->errors(), 'Validation Er
}

$project = Project::create($data);

return response(['project' => new ProjectResource($project), 'messag


}

/**
* Display the specified resource.
*
* @param \App\Models\Project $project
* @return \Illuminate\Http\Response
*/
public function show(Project $project)
{
return response(['project' => new ProjectResource($project), 'messag
}

/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Project $project
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Project $project)
{
$project->update($request->all());

return response(['project' => new ProjectResource($project), 'messag


}

/**
* Remove the specified resource from storage.
*
* @param \App\Models\Project $project
* @return \Illuminate\Http\Response
*/
public function destroy(Project $project)
{
$project->delete();

return response(['message' => 'Deleted']);


}
}

1. The index method will retrieve all the projects in the database with a success
message (Retrieved successfully) and returns a status code of 200.
2. The store method will validate and store a new project, just like the AuthController,
and returns a status code of 201, also a message of "Created successfully".
3. The show method will retrieve just one project that was passed through the
implicit route model binding, and also returns an HTTP code of 200 if successful.
4. The update method receives the HTTP request and the particular item that needs
to be edited as a parameter. It updates the project and returns the appropriate
response.
5. The destroy method also receives a particular project through implicit route
model binding and deletes it from the database.

Step 12: Create our Routes


Go to routes folder and click on api.php, and updates with the following code

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\API\AuthController;
use App\Http\Controllers\API\ProjectController;

/*
|--------------------------------------------------------------------------
| 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::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});

Route::post('register', [AuthController::class, 'register']);


Route::post('login', [AuthController::class, 'login']);

Route::apiResource('projects', ProjectController::class)->middleware('auth:a

We added a register route and login routes which are post routes and also an
apiResource route for projects utilizing the auth:api middleware.

Step 13: Testing


We are going to be testing our API with Postman, due to complexity and time, I might
not be able to explain everything on Postman, but observe the red squares on this
page

register a user

trying to get a user that does not exist

Login a registered user

In other to access the projects routes, we must authenticate the user, in other to
achieve this, we must add the user's token.
Copy the access token generated for the user when the user login in, click on
Authorization on postman and select the type, Bearer Token, and paste the token by
the input field by the right.

Retrieve all the projects, but no project was created


Create a project

Retrieve all the projects

Retrieve just 1 project

Update a project

Delete a project

Finally, we have come to the end of the article, if you follow the article religiously, you
will not make a mistake, but in case you can't follow all through, this is the link to the
repo

You can encourage me by clicking the heart button to show love, you are can also
leave a comment, suggestion, etc. You are also free to contact me through any of my
contact details.

click the link to view my profile and follow me

Visit my other posts

How to send email in Laravel 8 downwards


using Gmail
Kingsconsult ・ Oct 9 '20 ・ 4 min read
#php #laravel #webdev #beginners

How to upload data from a spreadsheet (excel)


in laravel 8 and laravel 7
Kingsconsult ・ Oct 6 '20 ・ 5 min read
#laravel #php #webdev #beginners
Creating and Consuming API (2 Part Series)

1 How to Create a Secure CRUD RESTful API in Laravel 8 and 7 Us…

2 How to consume RESTful APIs in Laravel 8 and Laravel 7

👋 Before you go
Do your career a favor. Join DEV. (The website you're on right now)

It takes one minute and it's fee.

Get started

Top comments (23)

Mian Salman • Apr 7 '21

You have not told us how to deal with access token because when I entered
data in 127.0.0.1:8000/api/register and in 127.0.0.1:8000/api/projects route
it shows login route not found and after adding this header X-Requested-With
I am getting unauthorized message and on register link it's showing
response to unauthorized access ?
how to deal with this I have 0 rows in user db ? show I make fake data first to
generate access token

benjaminv • Jul 12 '21 • Edited

You should have modified the api routes not the web routes. I made such
mistake at the beginning that resulted none of the url existed.
When I carefully corrected two typos in my scripts following the tutorial it
worked.

Vaidotas • May 20 '21


I agree, its confusing to say the least for beginner how to use postman in
particular.

Nahid Faraji • Oct 27 '21

I am having the same problem none of this url can be found.


surely, I am modified routes on api.php .

Mian Salman • Apr 8 '21

Now I figured out your first post is creating mess because you do not use
token in this route 127.0.0.1:8000/api/projects this is wrong implementation
as it is not using using token we make with passport auth.

benjaminv • Jul 12 '21

Hi Mian, could you please give more details of this? It worked okay as I
tried.

Vincent Tetteh • Jan 19 '21 • Edited

Target class
[App\Http\Controllers\App\Http\Controllers\API\ProjectController] does not
exist
please help me

Michael Angelo Mahinay • Jul 1 '21 • Edited

Hi @vincenttetteh ! In case you're still having this issue, you may refer to
this link:
stackoverflow.com/questions/638079...

We have the same problem and this solved mine

Vaidotas • May 20 '21

In header please add Key: Accept Value: application/json


Mian Salman • Apr 7 '21

If composer dumpautoload is not helping then check if you have proper


namespace declaration in ProjectController.php and double check for
typos in class name/route declaration.

GinsengSage • Apr 9 '21

Hello, do you decide this problem?

Badar Maulana • Feb 8 '21

testingProjectLaravel % php artisan migrate

Illuminate\Database\QueryException

SQLSTATE[HY000] [1049] Unknown database 'testingprojectlaravel' (SQL:


select * from information_schema.tables where table_schema =
testingProjectLaravel and table_name = migrations and table_type = 'BASE
TABLE')

at vendor/laravel/framework/src/Illuminate/Database/Connection.php:678
674▕ // If an exception occurs when attempting to run a query, we'll format
the error
675▕ // message to include the bindings with SQL, which will make this
exception a
676▕ // lot more helpful to the developer instead of just the database's
errors.
677▕ catch (Exception $e) {
➜ 678▕ throw new QueryException(
679▕ $query, $this->prepareBindings($bindings), $e
680▕ );
681▕ }
682▕

+33 vendor frames

34 artisan:37
Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\
Console\Input\ArgvInput),
Object(Symfony\Component\Console\Output\ConsoleOutput))

Mian Salman • Apr 7 '21

Your database is not set property or you have not any database with this
name testing.......

COCL オスマン • Dec 2 '20


How to logout?

COCL オスマン • Dec 5 '20


I got it

public function logout (Request $request) {


$accessToken = auth()->user()->token();
$token= $request->user()->tokens->find($accessToken);
$token->revoke();

return response(['message' => 'You have been successfully logge


}

benjaminv • Jul 12 '21

public function logout (Request $request) {


$accessToken = auth()->user()->token();
$token = $request->user()->tokens->find($accessToken);
$token->revoke();

return response([
'message' => 'You have been successfully logged out.',
], 200);
}

This makes sense I however got this error, do not know why,
Call to a member function token() on null
benjaminv • Jul 13 '21

I figured out what happened. Before you can log a user out via API, you
will need to pass authentication first and then log your login off.
Therefore the route logout has to be underneath the middleware auth.
For convenience I grouped it with the /user route that is used in this
tutorial.

Route::middleware('auth:api')->group(function (){
Route::get('/user', function (Request $request) {
return $request->user();
});
Route::post('logout', [
AuthController::class, 'logout'
]);
});

Abhaydix07 • May 4 '22

Thankyou Sir

COCL オスマン • Dec 5 '20


request project id=1 GET api.test/api/projects/1
But, how to request by project name? can you give me a sample?
Thank you.

andrey • Aug 5 '21 • Edited

after I`ve done all by hands I got an error. Please help)

Symfony\Component\Routing\Exception\RouteNotFoundException
Route [login] not defined.
192.168.20.105:8085/api/projects

Nahid Faraji • Oct 27 '21

same here. Did you figure it out?


simon-humanpixel • Feb 2 '22

this works for me - its important to register a user first and get their token
back and use it in future requests.

Naung Ye Htet • Oct 9 '21

can it be a security issue that exposing the id in resource?

View full discussion (24 comments)

Code of Conduct • Report abuse

Auth0 PROMOTED
Easy to implement, endless possibilities
With a few lines of code, you can have Auth0 by Okta integrated in any app
written in any language and any framework. 🚀 Start building for free today.
Sign up now

Kingsconsult

I am Kingsley Okpara, a Python and PHP Fullstack Web developer and tech writer, I also have
extensive knowledge and experience with JavaScript while working on applications developed
with VueJs.

LOCATION
Lagos, Nigeria
EDUCATION
Bsc.ed Mathematics, Enugu State University of Science and Technology, Enugu, Nigeria
WORK
Mid-level Web Developer at Plexada-Si
JOINED
Aug 5, 2019

More from Kingsconsult

Laravel Credit Card Validation


#php #laravel #webdev #security

Schedule a task to run at a specific time in laravel (CronJob)


#php #laravel #webdev #aws

Customize Laravel Jetstream (Registration and Login)


#jetstream #laravel #php #webdev

AWS PROMOTED
A data pipeline of helpful info
Fluent in SQL? This show’s for you.

Do you have questions about building efficient data architectures, navigating data virtualization
issues, or other common challenges? Get answers live from experts.

Learn More

You might also like