Restful APIs with Authentication Using laravel Passport

Build authentication into your Laravel API with Passport

SULE-BALOGUN OLANREWAJU
7 min readMar 31, 2020

Laravel already makes it easy to perform authentication via traditional login forms, but what about APIs? APIs typically use tokens to authenticate users and do not maintain session state between requests. Laravel makes API authentication a breeze using Laravel Passport, which provides a full OAuth2 server implementation for your Laravel application in a matter of minutes. Passport is built on top of the League OAuth2 server that is maintained by Andy Millington and Simon Hamp.

Install Laravel

Laravel utilizes Composer to manage its dependencies. So, before using Laravel, make sure you have Composer installed on your machine.

First, download the Laravel Installer using Composer:

composer global require laravel/installer

Once installed, the Laravel new command will create a fresh Laravel installation in the directory you specify. For instance, laravel new passport-api will create a directory named passport-api containing a fresh Laravel installation with all of Laravel’s dependencies already installed:

laravel new passport-api

Application Key

The next thing you should do after installing Laravel is set your application key to a random string. If you installed Laravel via Composer or the Laravel installer, this key has already been set for you by the command:

php artisan key:generate

Once we have our key generated in the .env file which is usually a clone of the .env.example file we can then establish database connection. If the application key is not set, your user sessions and other encrypted data will not be secure!

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=passport_api
DB_USERNAME=root
DB_PASSWORD=

Next I will proceed to generate a basic authentication scaffold on the fly:

// if you intend using laravel with Vue JS framework
php artisan ui vue --auth
// if you intend using laravel with React JS framework
php artisan ui react --auth
// for the sake of this tutorial we won't be using any JS framework
php artisan ui:auth

Thus far, here is what login.blade.php looks like which can be found in here on GitHub.

@extends('layouts.app')@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Login') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('api.login') }}">
@csrf
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<div class="col-md-6 offset-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
<label class="form-check-label" for="remember">
{{ __('Remember Me') }}
</label>
</div>
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Login') }}
</button>
@if (Route::has('password.request'))
<a class="btn btn-link" href="{{ route('password.request') }}">
{{ __('Forgot Your Password?') }}
</a>
@endif
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

Thus far, here is what register.blade.php looks like which can be found in here on GitHub.

@extends('layouts.app')@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Register') }}</div>
<div class="card-body">
<form method="POST" action="{{ route('api.register') }}">
@csrf
<div class="form-group row">
<label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>
<div class="col-md-6">
<input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>
@error('name')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">
@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Register') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

Here is how the route api.php file looks like which can be found in here on GitHub.

<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| 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::group(['middleware' => 'auth:api', 'namespace' => 'Api'], function(){

Route::get('/user', 'LoginController@alluser');

});
Route::group(['namespace' => 'Api'], function () {

Route::post('/login', 'LoginController@login')->name('api.login');
Route::post('/register', 'LoginController@register')->name('api.register');
});

Next I created a LoginController.php file for the project. This file can be found in here on GitHub.

<?phpnamespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Auth;
use App\User;
use Laravel\Passport\Client;
use Carbon\Carbon;
// use GuzzleHttp\Client;class LoginController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:api')->only('logout');
}
/**
* Show the application dashboard.
*
* @return \Illuminate\Contracts\Support\Renderable
*/

public function alluser(Request $request){
$user = User::all();
return response()->json(['user' => $user], 200);
}
public function login(Request $request)
{
$this->validate($request, [
'email' => ['required', 'string', 'email'],
'password' => ['required', 'string', 'min:8'],
]);
$credentials = request(['email', 'password']);
if(!Auth::attempt($credentials)){
return response()->json([
'errors' => [
'email' => ['could not sign you in with those credentials']
]
], 422);
}
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
if ($request->remember_me){
$token->expires_at = Carbon::now()->addWeeks(1);
}
$token->save();
return response()->json([
'data' => $user,
'access_token' => $tokenResult->accessToken,
'token_type' => 'Bearer',
'expires_at' => Carbon::parse(
$tokenResult->token->expires_at
)->toDateTimeString()
]);
} public function register(Request $request)
{
$this->validate($request, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
$user = User::create([
'name' => $request['name'],
'email' => $request['email'],
'password' => Hash::make($request['password']),
]);
if(!$user){
return response()->json(['success' => false, 'message'=> 'Registration failed']);
} return response()->json(['success' => true, 'message'=> 'Registration successful']);
}
}

Setting Up Passport

Laravel already makes it easy to perform authentication via authentication scaffold. APIs typically use tokens to authenticate users and help grant access to protected middleware on various routes.

INSTALLATION

To get started, install Passport via the Composer package manager:

composer require laravel/passport

The Passport service provider registers its own database migration directory with the framework, so you should migrate your database after installing the package. The Passport migrations will create the tables your application needs to store clients and access tokens:

php artisan migrate

Next, you should run the passport:install command. This command will create the encryption keys needed to generate secure access tokens, “personal access” and “password grant” clients which will be used to generate access tokens.

php artisan passport:install

After running this command, add the Laravel\Passport\HasApiTokens trait to your App\User model. This trait will provide a few helper methods to your model which allow you to inspect the authenticated user’s token and scopes:

<?phpnamespace App;use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
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',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}

Next, you should call the Passport::routes method within the boot method of your AuthServiceProvider. This method will register the routes necessary to issue access tokens and revoke access tokens, clients, and personal access tokens:

<?phpnamespace App\Providers;use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport;
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();
}
}

Finally, in your config/auth.php configuration file, you should set the driver option of the api authentication guard to passport. This will instruct your application to use Passport’s TokenGuard when authenticating incoming API requests:

'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],

Local Development Server

If you have PHP installed locally and you would like to use PHP’s built-in development server to serve your application, you may use the serve Artisan command. This command will start a development server at http://localhost:8000:

php artisan serve

To test API endpoint I recommend using POSTMAN. which is collaboration platform for API development.

Link to the project can be found here.

REFERENCE

Laravel Official Documentation

Happy Coding 🎉🎉🎉🎉🎉🎉🎉

--

--

SULE-BALOGUN OLANREWAJU
SULE-BALOGUN OLANREWAJU

Written by SULE-BALOGUN OLANREWAJU

Experienced Software Engineer with a demonstrated history of working in the computer software industry. Skilled in HTML, CSS, JS, Vue, Angular, PHP, Laravel

No responses yet