loading...
Cover image for Create API Rest with Laravel 7.X Passport Authentication And Implement Refresh Token (Part 1)

Create API Rest with Laravel 7.X Passport Authentication And Implement Refresh Token (Part 1)

azibom profile image Mohammad Reza Updated on 惻3 min read

you can find the newer article about this in here

Step 1. Install Laravel

With this command we install laravel

laravel new website

Step 2. Install Laravel Passport Package And Guzzle

Laravel Passport provides a full OAuth2 server implementation

composer require laravel/passport
composer require guzzlehttp/guzzle
composer require symfony/psr-http-message-bridge

Step 3. Run These Commands For Fixing Storage Permission

sudo chown -R $USER:www-data storage
sudo chmod -R 775 storage

Step 4. Run Migration

Create the tables that your application needs to store clients and access tokens

php artisan migrate

Step 5. Generate keys

With this commend you create "personal access" and "password grant" that you need them for generating access tokens

php artisan passport:install

Step 6. Add Trait To User Class

There are some helper functions in this trait

<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Passport\HasApiTokens;class User extends Authenticatable #chenged
{
    use Notifiable, HasApiTokens; #changed
...

Step 6. Call Passport Routes And Add Some Configs

call the Passport::routes method within the boot method of your AuthServiceProvider and change the token life time like this

<?php

namespace App\Providers;

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

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();
        Passport::tokensExpireIn(Carbon::now()->addDays(1));
        Passport::refreshTokensExpireIn(Carbon::now()->addDays(10));
    }
}

Step 7. Finally You Need To Change The Api Driver

you need change api drive in config/auth.php like this

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

Step 8. Create api route

<?php

use Illuminate\Support\Facades\Route;

Route::post('login', 'UserController@login');
Route::post('register', 'UserController@register');

Step 9. Create controller

php artisan make:controller UserController

Step 10. Complete the controller

<?php

namespace App\Http\Controllers;

use App\User; 
use Validator;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; 
use Laravel\Passport\Client as OClient; 

class UserController extends Controller
{
    public $successStatus = 200;

    public function login() { 
        if (Auth::attempt(['email' => request('email'), 'password' => request('password')])) { 
            $oClient = OClient::where('password_client', 1)->first();
            return $this->getTokenAndRefreshToken($oClient, request('email'), request('password'));
        } 
        else { 
            return response()->json(['error'=>'Unauthorised'], 401); 
        } 
    }

    public function register(Request $request) { 
        $validator = Validator::make($request->all(), [ 
            'name' => 'required', 
            'email' => 'required|email|unique:users', 
            'password' => 'required', 
            'c_password' => 'required|same:password', 
        ]);

        if ($validator->fails()) { 
            return response()->json(['error'=>$validator->errors()], 401);            
        }

        $password = $request->password;
        $input = $request->all(); 
        $input['password'] = bcrypt($input['password']); 
        $user = User::create($input); 
        $oClient = OClient::where('password_client', 1)->first();
        return $this->getTokenAndRefreshToken($oClient, $user->email, $password);
    }

    public function getTokenAndRefreshToken(OClient $oClient, $email, $password) { 
        $oClient = OClient::where('password_client', 1)->first();
        $http = new Client;
        $response = $http->request('POST', 'http://mylemp-nginx/oauth/token', [
            'form_params' => [
                'grant_type' => 'password',
                'client_id' => $oClient->id,
                'client_secret' => $oClient->secret,
                'username' => $email,
                'password' => $password,
                'scope' => '*',
            ],
        ]);

        $result = json_decode((string) $response->getBody(), true);
        return response()->json($result, $this->successStatus);
    }
}

Step 11. Now lets test it

php artisan serve

Step 12. It works like a charm

You first need to register like this

Alt Text

And then you can register and give your tokens again

Alt Text

In the next parts we will make some private routes that need token, handle the exceptions and implement refresh token scenario

Create API Rest with Laravel 7.X Passport Authentication And Implement Refresh Token (Part 2)

Posted on by:

azibom profile

Mohammad Reza

@azibom

azibom ... bom ... bom

Discussion

markdown guide
 

Hello,

Postman does not respond to me. It just says sending request.
I hit the endpoint with post on 127.0.0.1:8000/api/register and php artisan serve
serves on 127.0.0.1:8000.

Also, I setup my controller to respond with :
$response = $http->request('POST', '127.0.0.1:8000/oauth/token', [
......
]

If I set postman to hit the endpoint on 127.0.0.1/api/register (without :8000) I get
error 404 not found from nginx. (I have not set up nginx nor using it)

Any help?

 

same here, could you solve it ?

 
 

for mylemp-nginx/oauth/token :
you have two way for acces to your laravel project
1- php artisan serve ==>> localhost:8000
and
2-with your lamp or zamp or ... ==>> localhost/--project name--/public

for $response request in controller => localhost:8000/oauth/token
and
for postman => localhost/--project_name--/public/api/register or login

and header only Accept => Aplication/json

 

Nice Article,
but in an instance where the pasord is a pin and not the regular password how can that be inplemented?

                user = User::where("phone",$phone)->first();
                $user->name = $fullName;
                $user->email = $email;
                // $user->pin = $pin;
                $user->pin = $pin; // Hash::make($pin);

                $password = $request->pin;


                // $success['token'] =  $user->createToken('Gazelle')->accessToken; 
                // $success['name'] =  $user->name;

                $oClient = OClient::where('password_client', 1)->first();
                return $this->getTokenAndRefreshToken($oClient, $user->email, $password);

                $user->save();
 

hello bro thanks for that but i have a problem in the last step when i register with postman the server is blocked on sending request like this (see pictures) I guess there is a problem with route (/oauth/token)
by the way I have changed the route "mylemp-nginx/oauth/token" with my local with helper route('passport.token')

 

Great tutorial thanks.

Please why is this piece of code first executed outside then inside getTokenAndRefreshToken:

$oClient = OClient::where('password_client', 1)->first();

Executing before the function seems unnecessary.

 

Hi, I'd like to know how you set up

mylemp-nginx/oauth/token

in getTokenAndRefreshToken()

in order to use it

 

Hi, i dockerized my project and that is my container name, you should replace it with "localhost/oauth/token" or "localhost:8080/oauth/token" (if you are using "php artisan serv") and you don't need to set up anything

 

I was looking in documentation for the problem and found that having php and the web server (nginx) in different docker containers don't communicate by curl because php makes a call to localhost and not to the nginx container, for that reason it can't solve the url.

The solution is to put in the docker-compose.yml file in the container with php

extra_hosts:
- "url-container:172.18.0.3"

url-container: is the url our project.
172.18.0.3: The ip of the web server container (nginx in my case).

Change nginx-service to the name of the container where you have the web server.

I had to reboot everything to make it work, even my machine

My docker-compose.yml

version: '3.5'

networks:
servicesnet:
name: networkservices
driver: bridge

services:
nginx:
image: nginx:latest
container_name: nginx-service
ports:
- "80:80"
- "443:443"
networks:
- servicesnet
volumes:
- ../../mywebs:/var/www/localhost/htdocs
- ./pages/default:/var/www/localhost/htdocs/default
- ./nginx/config:/etc/nginx
- ./nginx/logs:/var/log/nginx
- ./nginx/certificates:/sites/ssl
links:
- php
php:
image: lep-alpine_php
container_name: php-service
volumes:
- ../../mywebs:/var/www/localhost/htdocs
- ./pages/default:/var/www/localhost/htdocs/default
- ./php:/etc/php7
networks:
- servicesnet
extra_hosts:
- "url-container:172.18.0.3"

 

Great tutorial! the whole refresh_token part is difficult to get from the documents You explained it well. Thanks

 

Hello can you help me understand why is it always

$oClient = OClient::where('password_client', 1)->first(); ? Why always one? Or like what table does this reference to?

 

Hi
I need one oclient user and password_client is a flag that i can use it and get a my oclient so i used it , if you have a better idea let's share it with me

 

Nice article.
Is there any github repo for this?
Coz, I can't find github.com/azibom
Thanks

 

HI !
im trying to make post on api/register but my server never response, any idea ?

 

I am having same issue. let me add more detail to it.
Following above installation process in laravel 7.0. when I use postman to check register api, user get registered and inserted into database but the part:
$response = $http->request('POST', env('APP_URL').'/oauth/token', [.....
does not return anything..
I searched on internet, someone said you have to pass timeout to Guzzle's http request. I did and it throws error "Connection time out".

 

have u run the php artisan serve?

 

Salam, I have question. By having Passport Authentication in the app, do I need to install Laravel make:auth? As we know, default Laravel auth includes forgot password, send confirmation, etc.

 

Hi! Great tutorial!!
One question, why your get the first oClient?:
$oClient = OClient::where('password_client', 1)->first();

Thanks!

 

I had to put
Passport::enableImplicitGrant(); in authserviceprovider boot method for using this method of sign in