Lumen porting of Laravel Passport. The idea come from https://github.com/dusterio/lumen-passport but try to make it transparent with original laravel passport
- PHP >= 7.3.0
- Lumen >= 8.0
First of all let's install Lumen Framework if you haven't already.
composer create-project --prefer-dist laravel/lumen lumen-app && cd lumen-app
Then install Lumen Passport (it will fetch Laravel Passport along):
composer require nomadnt/lumen-passport
Generate your APP_KEY and update .env with single command
sed -i "s|\(APP_KEY=\)\(.*\)|\1$(openssl rand -base64 24)|" .env
Configure your database connection (ie to use SQLite) This is how your .env file should looking after the changes
APP_NAME=Lumen
APP_ENV=local
APP_KEY=<my-super-strong-api-key>
APP_DEBUG=true
APP_URL=http://localhost:8000
APP_TIMEZONE=UTC
LOG_CHANNEL=stack
LOG_SLACK_WEBHOOK_URL=
DB_CONNECTION=sqlite
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
Copy the Lumen configuration folder to your project
cp -a vendor/laravel/lumen-framework/config config
Update guards
and provider
section of your config/auth.php to match Passport requirements
<?php
return [
...
'guards' => [
'api' => ['driver' => 'passport', 'provider' => 'users']
],
...
'providers' => [
'users' => ['driver' => 'eloquent', 'model' => \App\Models\User::class]
]
...
];
You need to change a little the bootstrap/app.php
file doing the following:
<?php
...
// enable facades
$app->withFacades();
// enable eloquent
$app->withEloquent();
...
$app->configure('app');
// initialize auth configuration
$app->configure('auth');
...
// enable auth and throttle middleware
$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,
'throttle' => Nomadnt\LumenPassport\Middleware\ThrottleRequests::class
]);
...
// register required service providers
// $app->register(App\Providers\AppServiceProvider::class);
$app->register(App\Providers\AuthServiceProvider::class);
$app->register(Laravel\Passport\PassportServiceProvider::class);
// $app->register(App\Providers\EventServiceProvider::class);
...
Create database.sqlite
touch database/database.sqlite
Lauch the migrations
php artisan migrate
Install Laravel passport
# Install encryption keys and other necessary stuff for Passport
php artisan passport:install
The previous command should give back to you an output similar to this:
Encryption keys generated successfully.
Personal access client created successfully.
Client ID: 1
Client secret: BxSueZnqimNTE0r98a0Egysq0qnonwkWDUl0KmE5
Password grant client created successfully.
Client ID: 2
Client secret: VFWuiJXTJhjb46Y04llOQqSd3kP3goqDLvVIkcIu
Now is time to register the passport routes necessary to issue access tokens and revoke access tokens, clients, and personal access tokens.
To do this open you app/Providers/AuthServiceProvider.php
and change the boot
function to reflect the example below.
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Carbon;
// don't forget to include Passport
use Nomadnt\LumenPassport\Passport;
class AuthServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Boot the authentication services for the application.
*
* @return void
*/
public function boot()
{
// register passport routes
Passport::routes();
// change the default token expiration
Passport::tokensExpireIn(Carbon::now()->addDays(15));
// change the default refresh token expiration
Passport::refreshTokensExpireIn(Carbon::now()->addDays(30));
}
}
Make sure your user model uses Passport's HasApiTokens
trait, eg.:
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Laravel\Passport\HasApiTokens;
use Laravel\Lumen\Auth\Authorizable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
class User extends Model implements AuthenticatableContract, AuthorizableContract
{
use HasApiTokens, Authenticatable, Authorizable;
// rest of the model
}
If you want to revoke or purge tokens on event based you have to create related Listeners and
register on your app/Http/Providers/EventServiceProvider.php
istead of using deprecated properties
Passport::$revokeOtherTokens = true;
and Passport::$pruneRevokedTokens = true;
First you need to make sure that EventServiceProvider
is registered on your bootstrap/app.php
<?php
...
// $app->register(App\Providers\AppServiceProvider::class);
$app->register(App\Providers\AuthServiceProvider::class);
$app->register(Laravel\Passport\PassportServiceProvider::class);
$app->register(App\Providers\EventServiceProvider::class);
...
Then you need to listen for AccessTokenCreated
event and register your required listeners
<?php
namespace App\Providers;
use Laravel\Lumen\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Laravel\Passport\Events\AccessTokenCreated' => [
'App\Listeners\RevokeOtherTokens',
'App\Listeners\PruneRevokedTokens',
]
];
}
Create the app/Listeners/RevokeOtherTokens.php
file and put the following content
<?php
namespace App\Listeners;
use Laravel\Passport\Events\AccessTokenCreated;
use Laravel\Passport\Token;
class RevokeOtherTokens
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param \App\Events\OrderShipped $event
* @return void
*/
public function handle(AccessTokenCreated $event)
{
Token::where(function($query) use($event){
$query->where('user_id', $event->userId);
$query->where('id', '<>', $event->tokenId);
})->revoke();
}
}
Create the app/Listeners/PruneRevokedTokens.php
file and put the following content
<?php
namespace App\Listeners;
use Laravel\Passport\Events\AccessTokenCreated;
use Laravel\Passport\Token;
class PruneRevokedTokens
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param \App\Events\AccessTokenCreated $event
* @return void
*/
public function handle(AccessTokenCreated $event)
{
Token::where(function($query) use($event){
$query->where('user_id', $event->userId);
$query->where('id', '<>', $event->tokenId);
$query->where('revoked', true);
})->delete();
}
}