📕

(EN) Laravel 8: Adding Passport Auth to API

2022/11/22に公開

https://github.com/TheBlindHawk/Laravel-8.0-API-auth-using-Passport

Installation

The first steps will be the installation steps for a new laravel project:

sudo service mysql start     //if mysql is not running
composer create-project laravel/laravel my-project-name
cd my-project-name
php artisan key:generate
php artisan serve

Navigate to http://localhost:8000 to check if your server is up and running.

Database

go to the .env file to check your database settings.

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

If you are running on Ubuntu I do not recommend using the root user.
Try accessing MySQL and creating a new one, unless you already have one.
See more details here.

sudo mysql -u root //sudo is necessary unless settings are changed.

mysql> USE mysql;
mysql> CREATE USER 'new_user'@'localhost' IDENTIFIED BY 'new_password';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'new_user'@'localhost';
mysql> UPDATE user SET plugin='mysql_native_password' WHERE User='new_user';
mysql> FLUSH PRIVILEGES;
mysql> exit;

sudo service mysql restart

Then change user and password in the .env file.

DB_USERNAME=new_user
DB_PASSWORD=new_password

Set up the passport

Run:

composer require laravel/passport
php artisan migrate
php artisan passport:install
php artisan passport:client --personal

Go to app/User.php and remove the following if found:

use Laravel\Sanctum\HasApiTokens;

Then add Laravel\Passport\HasApiTokens.
Making if finally look like this:

<?php

namespace App;

...
use Laravel\Passport\HasApiTokens; // include this

class User extends Authenticatable
{
    use HasApiTokens, ... ; // update this line

    ...
}

Switch to the app/Providers/AuthServiceProvider file and chenge the following three lines:

<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport; // add this 

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
         'App\Model' => 'App\Policies\ModelPolicy', // uncomment this line
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes(); // Add this
    }
}

In the app.php file add the passport service provider:

<?php

return [
    ...
    'providers' => [
        ...
        Laravel\Passport\PassportServiceProvider::class, //this line
    ],
    ...    
];

Finally switch to the config/auth file and change/add the 'api' section like so:

<?php

return [
    ...

    'guards' => [
        'web' => [
            ...
        ],

        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

    ...
];

Change/Create Users table

Now create your tables (follow the laravel guide if necessary for this step.
If you decided to directly add to the already existent User table and had to run

php artisan migrate:fresh

remember to run

php artisan passport:install --force
php artisan passport:client --personal

afterwards.

Login/Register

Back to the terminal run:

php artisan make:controller API/AuthController

This will create a file in app/Http/Controllers/API/AuthController.php.
Change it as following:

<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;

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'] = bcrypt($request->password);

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

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

        return response([ 'user' => $user, 'access_token' => $accessToken]);
    }

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

        if (!auth()->attempt($loginData)) {
            return response(['message' => 'Invalid Credentials']);
        }

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

        return response(['user' => auth()->user(), 'access_token' => $accessToken]);

    }
}

Now go to the routes/api.php and create yout login/register routes:

<?php

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

/*
|--------------------------------------------------------------------------
| 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', [AuthController::class,'register']);
Route::post('login', [AuthController::class,'login']);

...

Now you're all set for your api's!
To create an api that necessitates authentication add the auth:api middleware:

Route::get('users', [UserController::class,'index'])->middleware('auth:api'); //example code

restart to update your .env.
Use Ctrl+C to stop the service if still running:

php artisan cache:clear
php artisan route:clear
php artisan config:clear
php artisan serve

check your routes using

php artisan route:list

In my case I have the routes:
POST http://127.0.0.1:8000/api/login
POST http://127.0.0.1:8000/api/register
GET http://127.0.0.1:8000/api/users

Set up redirection route

To set up the redirection route add the following class unauthenticated inside app/Http/Middleware/Authenticate

<?php

namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;

class Authenticate extends Middleware
{
    /**
     * Get the path the user should be redirected to when they are not authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return string|null
     */
    protected function redirectTo($request)
    {
        if (! $request->expectsJson()) {
            return route('login');
        }
    }

    // new class
    protected function unauthenticated($request, array $guards)
    {
        abort(response()->json(
            [
                'api_status' => '401',
                'message' => 'UnAuthenticated',
            ], 401));
    }
}

Discussion