Laravel 8.x API Permissions Using Passport Scope

Hello Artisan

In this tutorial, I am coming with a brand new tutorial. In this tutorial, I will show you how we can login with laravel passport. Here I will create two login parts, one for the user and the other for admin. Only the admin can access all of the admin features, not the user. 

In this tutorial, we are going to learn about laravel passport. In this tutorial, I will show you step by step that how to create API authentication using laravel passport. In this laravel passport tutorial, I will also show you user access control using laravel passport scope.

Scopes allow your application's users to limit the actions a third-party application can perform on their behalf. Laravel passport token scope provides you beautiful services.

Scopes allow your API clients to request a specific set of permissions when requesting authorization to access an account. For example, if you are building an e-commerce application, not all API consumers will need the ability to place orders.

Instead, you may allow the consumers to only request authorization to access order shipment statuses. In this example we will also see laravel passport roles permissions from scratch so that you can understand all of that thing clearly.

So let's start our laravel passport API tutorial.

laravel-passport-scope-tutorial

 

Let's start building our Rest Api using laravel passport authentication with scopes.

Step 1: Install Laravel 

I am going to explain step by step from scratch so, we need fresh Laravel 7 application using bellow command

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

 

Step 2: Install Passport 

In this step we need to setup laravel/passpor package for passport method. so open your terminal and fire bellow command:

composer require laravel/passport

 

After successfully install package, open config/app.php file and add service provider.

config/app.php

'providers' => [

	....

	Laravel\Passport\PassportServiceProvider::class,

],

 

Step 3: Run Migration Command

After adding avobe service provider, we need to run migration command, after run migration command you will get several new tables in database. So, let's run bellow command:

php artisan migrate

 

Read also: Laravel 6 | Create API Authentication using Laravel Passport

 

Next, we need to install passport using command, Using passport:install command, it will create token keys for security. So let's run bellow command:

php artisan passport:install

 

Step 4: Passport Configuration

Now time to setup laravel passport confugartion. So let's do below things. We need HasApiTokens trait in our User model. So add it like below

app/User.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;
}

 

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
{
    
    protected $policies = [
        'App\Model' => 'App\Policies\ModelPolicy',
    ];

    public function boot()
    {
        $this->registerPolicies();
        Passport::routes();
    }
}

 

Now configure our auth.php file. Here our default api driber is token. Just replace it with passport.

config/auth.php

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

 

Step 5 : Setup API Route

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

routes/api.php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;


//Auth routes
Route::post('login', 'API\AuthController@login');
Route::post('register', 'API\AuthController@register');

// Route for admin permissions
Route::prefix('admin')->group(function() {
	Route::post('login', 'API\AuthController@adminLogin');
	Route::post('register', 'API\AuthController@adminRegister');
});

 

Step 6 :  Create & Setup Controller

In this step we need to create our AuthController. So let's create it and handle all of the methods here. Run below command to create it.

php artisan make:controller API/AuthController

 

After completing this step, copy the below code and paste it in your auth controller.

app/Http/Controllers/API/AuthController.php

namespace App\Http\Controllers\API;

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

class AuthController extends Controller
{
    public function login(Request $request)
    {
        
        $request->validate([
            'email' => 'required|email',
    		'password' => 'required',
        ]);
    	
        $credentials = $request->only(['email', 'password']);
        
    	if (Auth::attempt($credentials)) {
			
			$user = Auth::user();
			$success['token'] = $user->createToken('MyApp')->accessToken;
			return response()->json(['success' => $success], 200);
		}
		else {
			return response()->json(['error' => 'Unauthorized'], 401);
		}
    }
   
    public function register(Request $request)
    {
    	$request->validate([
            'name' => 'required',
			'email' => 'required|email',
			'password' => 'required',
			'c_password' => 'required|same:password',
        ]);

    	$user = User::create([
    		'name' => $request->name,
    		'email' => $request->email,
    		'password' => \Hash::make($request->password),
        ]);
        
    	$success['name'] = $user->name;
    	$success['token'] = $user->createToken('MyApp')->accessToken;
    	return response()->json(['success' => $success], 200);
    }
   
	public function adminLogin(Request $request)
	{
		$request->validate([
            'email' => 'required|email',
    		'password' => 'required',
        ]);

        $credentials = $request->only(['email', 'password']);
        
		if (Auth::attempt($credentials)) {
			
			$user = Auth::user();
			$success['token'] = $user->createToken('MyApp', ['*'])->accessToken;
			return response()->json(['success' => $success], 200);
		}
		else {
			return response()->json(['error' => 'Unauthorized'], 401);
		}
	}
	
	public function adminRegister(Request $request)
	{
		$request->validate([
            'name' => 'required',
			'email' => 'required|email',
			'password' => 'required',
			'c_password' => 'required|same:password',
        ]);

		$user = User::create([
			'name' => $request->name,
			'email' => $request->email,
			'password' => bcrypt($request->password),
		]);
		$success['name'] = $user->name;
		$success['token'] = $user->createToken('MyApp', ['*'])->accessToken;
		return response()->json(['success' => $success], 200);
	}

}

 

Look here carefully, if we request a token to have all the permissions I have defined, I would generate my token as like below.

$success['token'] = $user->createToken('MyApp', ['*'])->accessToken;

 

If we request a token for just one permission to perform a task, I would generate my tokens as like below:

For ‘update-task’ scope:

$success['token'] = $user->createToken('MyApp', ['update-task'])->accessToken;

 

But here we are going to use multiple scope together. That's why i am using (*) sign. Hope you will understand. You can read more about laravel passport scope using this link laravel paasport scope tutorial 

 

Read also :  Laravel 6 REST API with JWT Authentication with CRUD

 

Our login mechanism is completed, so we need to define our passport scope. You may define your API's scopes using the Passport::tokensCan method in the boot method of your AuthServiceProvider. The tokensCan method accepts an array of scope names and scope descriptions.

 

use Laravel\Passport\Passport;

Passport::tokensCan([
    'place-orders' => 'Place orders',
    'check-status' => 'Check order status',
]);

 

So open AuthServiceProvider and paste this below code like below

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();
        Passport::tokensCan([
            'edit' => 'can edit books available',
            'create' => 'can add new books',
            'delete' => 'can delete books',
        ]);
        Passport::routes();
    }
}

 

Step 7 :  Checking Scope

Now we need to add scope middleware. Passport includes two middleware that may be used to verify that an incoming request is authenticated with a token that has been granted a given scope. To get started, add the following middleware to the $routeMiddleware property of your app/Http/Kernel.php file:

app/Http/Kernel.php

protected $routeMiddleware = [
   .
   .
   'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class,
   'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class,
];

 

Now time to add this middleware in our routes. So open routes and paste this below code and update you api.php file.

routes/api.php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

//Auth routes
Route::post('login', 'API/AuthController@login');
Route::post('register', 'API/AuthController@register');

// Route for admin permissions
Route::prefix('admin')->group(function() {
	Route::post('login', 'API/AuthController@adminLogin');
	Route::post('register', 'API/AuthController@adminRegister');
});

Route::get('products', 'ProductController@index');
Route::get('products/{products}', 'ProductController@show');
Route::post('product', 'ProductController@store')->middleware(['auth:api', 'scope:create']);
Route::put('product/{product}', 'ProductController@update')->middleware(['auth:api', 'scope:edit']);
Route::delete('product/{product}', 'ProductController@destroy')->middleware(['auth:api', 'scope:delete']);

 

If you are using middle like above, there is no need to declare it in constructor method like below.

app/Http/Controllers/ProductController.php

namespace App\Http\Controllers;

use App\Book;
use Validator;
use Illuminate\Http\Request;
use App\Http\Resources\BookResource;

class ProductController extends Controller
{

    public function __construct()
    {
        $this->middleware(
            [
                'auth:api', 
                'scopes:edit,create,delete'
            ])->except(
                [
                    'index', 'show'
                ]
            );
    }
  
    public function index()
    {
        //return your all products
    }
  
    public function store(Request $request)
    {      
        //who has create scope, only he can store the products  
    }
  
    public function show($id)
    {
        //Show single product here
    }

    public function update(Request $request, $id)
    {
        //who has edit scope, only he can update the products
    }

    public function destroy($id)
    {
        //who has delete scope, only he can delete the products
    }

}

 

But here in controller we are using middleware scope in constructor method. So we can use our route like below.


// Route for api endpoints

Route::apiResource('products', 'ProductController');

 

Hope you have understand all the process. Well we are done everything.

Checking Scopes On A Token Instance

Once an access token authenticated request has entered your application, you may still check if the token has a given scope using the tokenCan method on the authenticated User instance.

 

Route::get('/products', function (Request $request) {

    if ($request->user()->tokenCan('place-orders')) {

        //user has authorised to perform this operation

    }

});

 

Check git repository : Laravel Passport Scope 

 

Thanks you guys for reading this article from my site, hope you have learned something new from this laravel passport scope tutorial.

 

#laravel #passport #api #auth #acl #permissions #roles #passport-scope #rest-api #laravel-passport #laravel-6 #laravel-7 #packages