API Rest with Laravel 5.6 Passport Authentication — Confirm account + notifications (Part 2) (ok)

https://medium.com/modulr/create-api-authentication-passport-in-laravel-5-6-confirm-account-notifications-part-2-5e221b021f07

Ví dụ đã thực hiện :)

C:\xampp\htdocs\blog\app\Http\Controllers\AuthController.php

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;
use App\User;
use App\Notifications\SignupActivate;
class AuthController extends Controller {
  /**
   * Create user
   *
   * @param  [string] name
   * @param  [string] email
   * @param  [string] password
   * @param  [string] password_confirmation
   * @return [string] message
   */
  public function signup(Request $request) {
    $request->validate([
      'name'     => 'required|string',
      'email'    => 'required|string|email|unique:users',
      'password' => 'required|string|confirmed',
    ]);
    $user = new User([
      'name'     => $request->name,
      'email'    => $request->email,
      'password' => bcrypt($request->password),
      'activation_token' => str_random(60)
    ]);
    $user->save();
    $user->notify(new SignupActivate($user));
    return response()->json(['message' => 'Successfully created user!'], 201);
  }
  /**
   * Login user and create token
   *
   * @param  [string] email
   * @param  [string] password
   * @param  [boolean] remember_me
   * @return [string] access_token
   * @return [string] token_type
   * @return [string] expires_at
   */
    public function signupActivate($token)
{
    $user = User::where('activation_token', $token)->first();
    if (!$user) {
        return response()->json([
            'message' => 'This activation token is invalid.'
        ], 404);
    }
    $user->active = true;
    $user->activation_token = '';
    $user->save();
    return $user;
}
public function login(Request $request)
{
    $request->validate([
        'email' => 'required|string|email',
        'password' => 'required|string',
        'remember_me' => 'boolean'
    ]);
    $credentials = request(['email', 'password']);
    $credentials['active'] = 1;
    $credentials['deleted_at'] = null;
    if(!Auth::attempt($credentials))
        return response()->json([
            'message' => 'Unauthorized'
        ], 401);
    $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([
        'access_token' => $tokenResult->accessToken,
        'token_type' => 'Bearer',
        'expires_at' => Carbon::parse($tokenResult->token->expires_at)->toDateTimeString()
    ]);
}
  /**
   * Logout user (Revoke the token)
   *
   * @return [string] message
   */
  public function logout(Request $request) {
    $request->user()->token()->revoke();
    return response()->json([
      'message' => 'Successfully logged out',
    ]);
  }
  /**
   * Get the authenticated User
   *
   * @return [json] user object
   */
  public function user(Request $request) {
    return response()->json($request->user());
  }
}

C:\xampp\htdocs\blog\app\Notifications\SignupActivate.php

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class SignupActivate extends Notification {
  use Queueable;

  /**
   * Create a new notification instance.
   *
   * @return void
   */
  public function __construct() {
    //
  }

  /**
   * Get the notification's delivery channels.
   *
   * @param  mixed  $notifiable
   * @return array
   */
  public function via($notifiable) {
    return ['mail'];
  }

  /**
   * Get the mail representation of the notification.
   *
   * @param  mixed  $notifiable
   * @return \Illuminate\Notifications\Messages\MailMessage
   */
  public function toMail($notifiable) {
    $url = url('/api/auth/signup/activate/' . $notifiable->activation_token);
    return (new MailMessage)
      ->subject('Confirm your account')
      ->line('Thanks for signup! Please before you begin, you must confirm your account.')
      ->action('Confirm Account', url($url))
      ->line('Thank you for using our application!');
  }

  /**
   * Get the array representation of the notification.
   *
   * @param  mixed  $notifiable
   * @return array
   */
  public function toArray($notifiable) {
    return [
      //
    ];
  }

}

C:\xampp\htdocs\blog\routes\api.php

<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::middleware('auth:api')->get('/user', function (Request $request) {
  return $request->user();
});
Route::group([
    'prefix' => 'auth'
], function () {
    Route::post('login', 'AuthController@login');
    Route::post('signup', 'AuthController@signup');
    Route::get('signup/activate/{token}', 'AuthController@signupActivate');
  
    Route::group([
      'middleware' => 'auth:api'
    ], function() {
        Route::get('logout', 'AuthController@logout');
        Route::get('user', 'AuthController@user');
    });
});

C:\xampp\htdocs\blog\app\User.php

<?php
namespace App;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable {
  use Notifiable, HasApiTokens, SoftDeletes;
  protected $dates = ['deleted_at'];
  /**
   * The attributes that are mass assignable.
   *
   * @var array
   */
  protected $fillable = [
    'name', 'email', 'password', 'active', 'activation_token',
  ];
  /**
   * The attributes that should be hidden for arrays.
   *
   * @var array
   */
  protected $hidden = [
    'password', 'remember_token', 'activation_token',
  ];
  /**
   * The attributes that should be cast to native types.
   *
   * @var array
   */
  protected $casts = [
    'email_verified_at' => 'datetime',
  ];
}

C:\xampp\htdocs\blog\app\Providers\AuthServiceProvider.php

<?php

namespace App\Providers;

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

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();
    }
}

C:\xampp\htdocs\blog\config\auth.php

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

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

API Rest with Laravel 5.6 Passport Authentication — Confirm account + notifications (Part 2)

Step 1. Add columns in users table

In first step, we add two columns active and activation_token also we add thesoftDeletes trait in database/migrations/xxxx_create_users_table.php migration file.

<?phpuse Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->boolean('active')->default(false);
            $table->string('activation_token');
            $table->rememberToken();
            $table->timestamps();
            $table->softDeletes();
        });
    }
...

Next, we add SoftDeletes trait, fillable and hidden attributes in your App\User model.

<?php
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;
use Illuminate\Database\Eloquent\SoftDeletes;class User extends Authenticatable
{
    use Notifiable, HasApiTokens, SoftDeletes;    protected $dates = ['deleted_at'];    protected $fillable = [
        'name', 'email', 'password', 'active', 'activation_token'
    ];    protected $hidden = [
        'password', 'remember_token', 'activation_token'
    ];}

After, open your terminal or command prompt and run bellow command:

php artisan migrate:refresh

Step 2. Create confirm account notification

In your terminal or command prompt run bellow command:

php artisan make:notification SignupActivate

This command will create app/Notifications/SignupActivate.php file, in this file determines on which channels the notification will be delivered. In our case we use mail

public function via($notifiable)
{
    return ['mail'];
}

After that we make our email notification.

public function toMail($notifiable)
{
    $url = url('/api/auth/signup/activate/'.$notifiable->activation_token);    return (new MailMessage)
        ->subject('Confirm your account')
        ->line('Thanks for signup! Please before you begin, you must confirm your account.')
        ->action('Confirm Account', url($url))
        ->line('Thank you for using our application!');
}

Step 3: Create and send token to confirm account

We have to update app/Http/Controllers/AuthController.php controller and update signup api method. So let’s update AuthController and put bellow code:

<?php...
use App\Notifications\SignupActivate;
class AuthController extends Controller
{
...    public function signup(Request $request)
    {
        $request->validate([
            'name' => 'required|string',
            'email' => 'required|string|email|unique:users',
            'password' => 'required|string|confirmed'
        ]);        $user = new User([
            'name' => $request->name,
            'email' => $request->email,
            'password' => bcrypt($request->password),
            'activation_token' => str_random(60)
        ]);        $user->save();        $user->notify(new SignupActivate($user));        return response()->json([
            'message' => 'Successfully created user!'
        ], 201);
    }
}

When create new account will receive a email with the link to activate account. The next step we create the route and method to activate account.

Step 4. Add Activation Account Route

We will add new route signup/activate/{token} inroutes/api.php file. So, let’s add new route on that file.

<?phpuse Illuminate\Http\Request;
Route::group([
    'prefix' => 'auth'
], function () {
    Route::post('login', 'AuthController@login');
    Route::post('signup', 'AuthController@signup');
    Route::get('signup/activate/{token}', 'AuthController@signupActivate');
  
    Route::group([
      'middleware' => 'auth:api'
    ], function() {
        Route::get('logout', 'AuthController@logout');
        Route::get('user', 'AuthController@user');
    });
});

Step 6. Confirm account (activate user)

We create the method signupActivate in to app/Http/Controllers/AuthController.php controller to activate user account.

public function signupActivate($token)
{
    $user = User::where('activation_token', $token)->first();    if (!$user) {
        return response()->json([
            'message' => 'This activation token is invalid.'
        ], 404);
    }    $user->active = true;
    $user->activation_token = '';
    $user->save();    return $user;
}

Step 7. Validate account

To validate that account is active and has not been deleted we update login method of app/Http/Controllers/AuthController.php controller.

public function login(Request $request)
{
    $request->validate([
        'email' => 'required|string|email',
        'password' => 'required|string',
        'remember_me' => 'boolean'
    ]);    $credentials = request(['email', 'password']);
    $credentials['active'] = 1;
    $credentials['deleted_at'] = null;    if(!Auth::attempt($credentials))
        return response()->json([
            'message' => 'Unauthorized'
        ], 401);    $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([
        'access_token' => $tokenResult->accessToken,
        'token_type' => 'Bearer',
        'expires_at' => Carbon::parse($tokenResult->token->expires_at)->toDateTimeString()
    ]);
}

Now we are ready to run our example so run bellow command to quick run:

php artisan serve

Tests

Now, we can simple test by rest client tools (Postman), So I test it and you can see below screenshots.

In this api you have to set two header as listed below:

Content-Type: application/json
X-Requested-With: XMLHttpRequest

SignupActivate

Thanks for reading! I’m Alfredo Barrón, Feel free to connect with me via Twitter.

Part 1. Passport Authentication Part 2. Confirm account + notifications Part 3. Generate avatar Part 4. Reset Password Part 5. Send Notifications with Queues on Redis

Resources

-GitHub -Postman collections

References

-Laravel Notifications

Last updated