Using Laravel Passport to authenticate access to your API

The client credentials grant for machine-to-machine authentication

Ed Hertzog
4 min readJun 6, 2018

Potential use case: you have a component that you have developed for a CMS which must access an API to retrieve data using RESTful requests.

Additional characteristics of your application:

  • Your web server has an interface exposed via a routable IP address and port
  • The component communicates with an API via a non-routable address
  • The component communicates via SSL
  • The component communicates through a firewall, which whitelists your web server
  • You would like an added layer of security and would like to control access to the API on your internal/non-routable network

This assumes you have already set up REST API with Laravel Resources.

To get started, install Passport via the Composer package manager, while in your /api directory:

composer require laravel/passport

The Passport service provider registers its own database migration directory with the framework, so you should migrate your database after registering the provider. The Passport migrations will create the tables your application needs to store clients and access tokens:

php artisan migrate

Next, you should run the passport:install command. This command will create the encryption keys needed to generate secure access tokens. In addition, the command will create "personal access" and "password grant" clients which will be used to generate access tokens:

php artisan passport:install

After running this command, add the Laravel\Passport\HasApiTokens trait to your App\Usermodel. This trait will provide a few helper methods to your model which allow you to inspect the authenticated user's token and scopes:

<?phpnamespace App;use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
}

Next, you should call the Passport::routes method within the boot method of your AuthServiceProvider. This method will register the routes necessary to issue access tokens and revoke access tokens, clients, and personal access tokens:

<?phpnamespace 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::routes();
}
}

Finally, in your config/auth.php configuration file, you should set the driver option of the api authentication guard to passport. This will instruct your application to use Passport's TokenGuard when authenticating incoming API requests:

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

The documentation recommends: When deploying Passport to your production servers for the first time, you will likely need to run the passport:keys command. This command generates the encryption keys Passport needs in order to generate access token. The generated keys are not typically kept in source control:

php artisan passport:keys

That command will generate these files:

api/storage/oauth-private.key
api/storage/oauth-public.key

Make sure they are actually generated. If they are not, this authorization scheme won’t work. The default .gitignore file Laravel uses will not include these files in your repo, so you will need to generate in different environments.

Token Lifetimes

By default, Passport issues long-lived access tokens that expire after one year. If you would like to configure a longer / shorter token lifetime, you may use the tokensExpireIn and refreshTokensExpireIn methods. These methods should be called from the boot method of your AuthServiceProvider:

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Passport::routes(); Passport::tokensExpireIn(now()->addDays(15)); Passport::refreshTokensExpireIn(now()->addDays(30));
}

The passport:client Command

The simplest way to create a client (aka API key), which will access your API, is using the passport:client artisancommand. This command may be used to create your own clients for testing your OAuth2 functionality. When you run the client command, Passport will prompt you for more information about your client and will provide you with a client ID and secret. It should be noted, the client ID needs to be an integer. Trying to use a string will throw an error:

php artisan passport:client

Be sure to save the output data somewhere. You’ll need that.

Go to a controller whose routes you wish to control and attache the middleware:

public function __construct()
{
$this->middleware('client');
}

Now it is time to prove this works. You’ll need a tool to test your API, such as Insomnia, if you don’t already have one.

From the step above, you should have saved a client id and a secret string. You will need that to generate a token by sending a POST to /oauth/token with the following JSON:

Of course, the secret should be the value for clicent_secret and client_id should have the correct value too. After you post that data, you should receive JSON back with a very long string as the value for access_token.

The next step is to test that token with the controller you just secured above, by attaching the middleware. You can do so by sending a HEADER property of “Authorization” with a corresponding value of “Bearer” followed by a space and the access_token you just generated above.

If all goes well, you should get data back. If this is set up properly, changing one character in the access_token in the header, should result in an error.

When making requests to your API, assuming you have attached the middleware to the relevant controllers, you will need to pass the HEADER data in order to be authenticated. And, assuming you followed all of these steps, you should have a properly secured API using Laravel Passport and the client credentials grant.

--

--