Laravel is one of my favorite frameworks, not because it is the best but it provides far better developer experience compared to any other frameworks. Laravel 5.3 comes with a handful of new features like Passport, Scout, Notifications, etc. that will make our life even easier.

Passport is a Laravel package which provides a complete OAuth2 implementation out of the box. It is built on top of OAuth2 server library by The League of Extraordinary Packages. If you have ever tried to set up an OAuth server, you know it's not easy to get everything right. Now we can install Passport and with some configuration, our application will be OAuth2 ready.

Before we dive into the Passport, it's important to understand a few concepts. Especially what is a Grant and the different types Grants in OAuth2.

When the client application wants to access a protected resource from the API server, it should present an access token to authenticate the request. Grant is nothing but a way of getting the access token from the authorization server. There are five types of Grants, four of them are for obtaining an access token whereas the other one is to refresh/renew an existing access token.

Authorization Code grant

Authorization Code grant is the most common flow, which is used when we want to allow third party application developers to access protected information from our application. The client application must obtain the user's authorization to access the data.

Most of the popular APIs implements this grant. In the case of Facebook, when the user wants to login to our website, we tell the user to login in Facebook by redirecting them to Facebook. After login, Facebook asks the user if they want to authorize our application to access the user information on Facebook. Once approved, the user will be redirected back to our application along with an authorization code. Our application then uses this code to obtain an access token from Facebook, which can be used to get the user details. This process is called 3-Legged OAuth.

Implicit Grant

Implicit grant is similar to authorization code grant, except that the authorization server sends the access token instead of the authorization code. So this flow doesn't need the third step to obtain the access token. You may wonder why would we need this when Authorization Code grant is better. Well, the Authorization Code grant requires a server side code to talk to the authorization server (Facebook) and exchange the code for the access token. If what we have is a JavaScript app that just live in the browser, it will be difficult to get the access token using Authorization Code flow. In those situations, we can use the Implicit grant.

Resource Owner Password Credentials Grant

This grant is suitable when dealing with the client that we trust, like a mobile app for our own website. In this case, the client sends the user's login credentials to the authorization server and the server directly issues the access token.

Resource Owner == User

Client Credentials Grant

This grant is useful when the Client/App is the resource owner and no user interaction is required (machine to machine communication). For example, if the app wants to show a catalog to the user or store some data related to the app on the server.

Refresh token grant

When the server issues an access token, it also sets an expiry for the access token. Refresh token grant is used when we want to refresh the access token once it is expired. In this case, authorization server will send a refresh token while issuing the access token, which can be used to request a new access token. Note that this flow is not available when using Implicit Grant.

This article is a shorter, step by step version of how to use Passport, which will help you to quickly set up the server without going into the details. For more details, please refer the documentation.

Setting up OAuth2 Server

To set up the OAuth server, first we will create a new Laravel 5.3 project.

laravel new passport-server

Now update the database credentials in .env file.

DB_HOST="127.0.0.1"
DB_PORT=3306
DB_DATABASE="laravel"
DB_USERNAME="root"
DB_PASSWORD="root"

Let's also create the Auth scaffold

php artisan make:auth

Now we will install the Passport package using composer.

composer require laravel/passport

After installing the package, we need to register the Passport service provider in the providers array of config/app.php

Laravel\Passport\PassportServiceProvider::class

Now we are ready to run the database migrations.

php artisan migrate

After installing the package using composer, we need to run passport:install command, which will create the encryption keys required by the OAuth2 library. It will also create a personal access and password clients for us.

php artisan passport:install

Now add Laravel\Passport\HasApiTokens trait in to the App\User model.

<?php
// app/User.php
namespace App;

use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}

Update the authentication guard driver for api in config/auth.php

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

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

Register Passport routes in RouteService provider.

<?php
namespace App\Providers;

use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class RouteServiceProvider extends ServiceProvider
{
...

    /**
     * Define the routes for the application.
     *
     * @return void
     */
    public function map()
    {
        $this->mapWebRoutes();

        $this->mapApiRoutes();

        Passport::routes();
        //
    }

...
}

That's it! We have successfully setup the OAuth server and ready to create our first client application. Before we create a client, we should register a user on the website, to whom this client should be assigned to. Once it is done, go to the project folder in the command line and run.

php artisan passport:client 

By default, it will create an "Authorization Code" grant client. We should provide a name for this client (app name), callback URL and a user id to whom this client should be assigned. Callback URL is used to redirect the users back the client application after authorization.

Once created, it will return a client id a secret, which are required to get an access token.

To test our server, we will start a new client project, which should have two routes.

Route::get('/redirect', function () {

    $query = http_build_query([
        'client_id' => '3',
        'redirect_uri' => 'http://client.local/callback',
        'response_type' => 'code',
        'scope' => ''
    ]);

    return redirect('http://server.local/oauth/authorize?'.$query);
});

This route will redirect the user to our OAuth server, which is currently running on http://server.local. client_id, redirect_uri and response_code are the required parameter. redirect_uri is the URL that we provided while creating the client. response_code tells that we want to get the Authorization code.

OAuth server will then ask the user if he/she want to authorize our client app to access their data. If the user approves, the server will redirect back to the http://client.local/callback URL with the authorization code. If the user denies the request, it will redirect back with access_denied error.

Once the client gets the authorization code, it should make a request to retrieve the access token.

Route::get('/callback', function (Illuminate\Http\Request $request) {
    $http = new \GuzzleHttp\Client;

    $response = $http->post('http://server.local/oauth/token', [
        'form_params' => [
            'client_id' => '3',
            'client_secret' => 'iX8YZrI198wwlFrBpfNSl8C2h7eTk1rQKMg28Qcm',
            'grant_type' => 'authorization_code',
            'redirect_uri' => 'http://client.local/callback',
            'code' => $request->code,
        ],
    ]);
    return json_decode((string) $response->getBody(), true);
});

Here we should mention the grant_type as authorization_code and the redirect_uri should match to the one that we provided earlier. code is the authorization code that we received from the OAuth server. If the post request is successful, it will return us an access token and a refresh token.

Now we can use this access token to get the user's details. Let's add the following route into the routes/api.php in OAuth server.

Route::get('/user/{user}', function (App\user $user) {
    return $user->email;
});

Now, from the command line, we can make a request to our OAuth server on behalf of the user.

curl -H "Authorization: Bearer long_access_token_string" http://server.local/api/user/1

We should be able to see the email address of the authorized user.

Summary

Laravel Passport is an awesome package which provides a full OAuth2 server implementation. We can quickly setup a secure API server without the need to fight with different libraries and their configurations. Passport comes with a web UI to register and manage client applications and access tokens. We can also specify the access token scopes and there is a Middleware which we can use to verify the access token has required scopes.

blog comments powered by Disqus