Advertisement
  1. Code
  2. PHP
  3. Laravel

Set Up an OAuth2 Server Using Passport in Laravel

Scroll to top

In this article, we’re going to explore how you could set up a fully fledged OAuth2 server in Laravel using the Laravel Passport library. We’ll go through the necessary server configurations along with a real-world example to demonstrate how you could consume OAuth2 APIs.

I assume that you’re familiar with the basic OAuth2 concepts and flow as we’re going to discuss them in the context of Laravel. In fact, the Laravel Passport library makes it pretty easy to quickly set up an OAuth2 server in your application. Thus, other third-party applications are able to consume APIs provided by your application.

In the first half of the article, we’ll install and configure the necessary libraries, and the second half goes through how to set up demo resources in your application and consume them from third-party applications.

Server Configurations

In this section, we're going to install the dependencies that are required in order to make the Passport library work with Laravel. After installation, there's quite a bit of configuration that we'll need to go through so that Laravel can detect the Passport library.

Install the Laravel Passport Library

Let's go ahead and install the Passport library using composer.

1
$composer require laravel/passport

That's pretty much it as far as the Laravel Passport library installation is concerned. Now let's make sure that Laravel knows about it.

Enable the Passport Service

Working with Laravel, you're probably aware of the concept of a service provider that allows you to configure services in your application. Thus, whenever you want to enable a new service in your Laravel application, you just need to add an associated service provider entry in the config/app.php.

If you're not aware of Laravel service providers yet, I would strongly recommend that you do yourself a favor and go through this introductory article that explains the basics of service providers in Laravel.

In our case, we just need to add the PassportServiceProvider provider to the list of service providers in config/app.php, as shown in the following snippet.

1
...
2
...
3
'providers' => [
4
 
5
        /*

6
         * Laravel Framework Service Providers...

7
         */
8
        Illuminate\Auth\AuthServiceProvider::class,
9
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
10
        Illuminate\Bus\BusServiceProvider::class,
11
        Illuminate\Cache\CacheServiceProvider::class,
12
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
13
        Illuminate\Cookie\CookieServiceProvider::class,
14
        Illuminate\Database\DatabaseServiceProvider::class,
15
        Illuminate\Encryption\EncryptionServiceProvider::class,
16
        Illuminate\Filesystem\FilesystemServiceProvider::class,
17
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
18
        Illuminate\Hashing\HashServiceProvider::class,
19
        Illuminate\Mail\MailServiceProvider::class,
20
        Illuminate\Notifications\NotificationServiceProvider::class,
21
        Illuminate\Pagination\PaginationServiceProvider::class,
22
        Illuminate\Pipeline\PipelineServiceProvider::class,
23
        Illuminate\Queue\QueueServiceProvider::class,
24
        Illuminate\Redis\RedisServiceProvider::class,
25
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
26
        Illuminate\Session\SessionServiceProvider::class,
27
        Illuminate\Translation\TranslationServiceProvider::class,
28
        Illuminate\Validation\ValidationServiceProvider::class,
29
        Illuminate\View\ViewServiceProvider::class,
30
 
31
        /*

32
         * Package Service Providers...

33
         */
34
        Laravel\Tinker\TinkerServiceProvider::class,
35
 
36
        /*

37
         * Application Service Providers...

38
         */
39
        App\Providers\AppServiceProvider::class,
40
        App\Providers\AuthServiceProvider::class,
41
        App\Providers\BroadcastServiceProvider::class,
42
        App\Providers\EventServiceProvider::class,
43
        App\Providers\RouteServiceProvider::class,
44
        Laravel\Passport\PassportServiceProvider::class,
45
],
46
...
47
...

Create the Database Tables

Now, we need to run the migrate artisan command, which creates the necessary tables in a database for the Passport library.

1
$php artisan migrate

To be precise, it creates following the tables in the database.

1
oauth_access_tokens
2
oauth_auth_codes
3
oauth_clients
4
oauth_personal_access_clients
5
oauth_refresh_tokens

Create a Pair of Public and Private Keys

Next, we need to generate a pair of public and private keys that will be used by the Laravel Passport library for encryption. As expected, the Passport library provides an artisan command to create them easily.

1
$php artisan passport:install
2
Encryption keys generated successfully.
3
Personal access client created successfully.
4
Client ID: 1
5
Client secret: ae2gNU5RnxucI9klOkKCLC76JVlbVYndE5v1Of70
6
Password grant client created successfully.
7
Client ID: 2
8
Client secret: GQyBurXrkKwGrUahcls25GOB4yEnxScfmFlgb3io

That should have created keys at storage/oauth-public.key and storage/oauth-private.key. It also creates some demo client credentials that we'll get back to later.

Oauthify the User Model

Moving ahead, let's oauthify the existing User model class which Laravel uses for authentication. To do that, we need to add the HasApiTokens trait to the User model class. Let's do that as shown in the following snippet.

1
<?php
2
 
3
namespace App;
4
 
5
use Illuminate\Notifications\Notifiable;
6
use Illuminate\Foundation\Auth\User as Authenticatable;
7
use Laravel\Passport\HasApiTokens;
8
 
9
class User extends Authenticatable
10
{
11
    use HasApiTokens;
12
 
13
    /**

14
     * The attributes that are mass assignable.

15
     *

16
     * @var array

17
     */
18
    protected $fillable = [
19
        'name', 'email', 'password',
20
    ];
21
 
22
    /**

23
     * The attributes that should be hidden for arrays.

24
     *

25
     * @var array

26
     */
27
    protected $hidden = [
28
        'password', 'remember_token',
29
    ];
30
}

The HasApiTokens trait contains helper methods that are used to validate tokens in the request and check the scope of the resources being requested in the context of the currently authenticated user.

Register the Passport Routes

Further, we need to register the routes provided by the Passport library with our Laravel application. These routes will be used for standard OAuth2 operations like authorization, requesting access tokens, and the like.

In the boot method of the app/Providers/AuthServiceProvider.php file, let's register the routes of the Passport library. You also need to add the use Laravel\Passport\Passport line at the beginning of this file.

1
...
2
/**

3
  * Register any authentication / authorization services.

4
  *

5
  * @return void

6
  */
7
public function boot()
8
{
9
    $this->registerPolicies();
10
     
11
    Passport::routes();
12
}
13
...
14
...

Tweak the API Driver Configuration

Last but not least, we need to change the api driver from token to passport in the config/auth.php file, as we're going to use the Passport library for the API authentication.

1
'guards' => [
2
    'web' => [
3
        'driver' => 'session',
4
        'provider' => 'users',
5
    ],
6
 
7
    'api' => [
8
        'driver' => 'passport',
9
        'provider' => 'users',
10
        'hash' => false,
11
    ],
12
],

So far, we've done everything that's required as far as the OAuth2 server configuration is concerned.

Set Up the Demo Resources

In the previous section, we did all the hard work to set up the OAuth2 authentication server in our application. In this section, we'll set up a demo resource that could be requested over the API call.

We will try to keep things simple. Our demo resource returns the user information provided that there's a valid uid parameter present in the GET request.

Let's create a controller file app/Http/Controllers/UserController.php with the following contents.

1
<?php
2
namespace App\Http\Controllers;
3
 
4
use App\Http\Controllers\Controller;
5
use Illuminate\Http\Request;
6
use App\User;
7
 
8
class UserController extends Controller
9
{
10
    public function get(Request $request)
11
    {
12
      $user_id = $request->get("uid", 0);
13
      $user = User::find($user_id);
14
      return $user;
15
    }
16
}

As usual, you need to add an associated route as well, which you are supposed to add in the routes/web.php file. But what we are talking about is the API route, and thus it needs special treatment.

The API routes are defined in the routes/api.php file. So let's go ahead and add our custom API route, as shown in the following snippet.

1
<?php
2
 
3
use Illuminate\Http\Request;
4
 
5
/*

6
|--------------------------------------------------------------------------

7
| API Routes

8
|--------------------------------------------------------------------------

9
|

10
| Here is where you can register API routes for your application. These

11
| routes are loaded by the RouteServiceProvider within a group which

12
| is assigned the "api" middleware group. Enjoy building your API!

13
|

14
*/
15
 
16
Route::middleware('auth:api')->get('/user', function (Request $request) {
17
    return $request->user();
18
});
19
 
20
// custom API route

21
Route::middleware('auth:api')->get('/user/get', 'UserController@get');

Although we've defined it as /user/get, the effective API route is /api/user/get, and that's what you should use when you request a resource over that route. The api prefix is automatically handled by Laravel, and you don't need to worry about that!

In the next and last section, we'll discuss how you could create client credentials and consume the OAuth2 API.

How to Consume OAuth2 APIs

Now that we've set up the OAuth2 server in our application, any third party can connect to our server with OAuth and consume the APIs available in our application.

First of all, third-party applications must register with our application in order to be able to consume APIs. In other words, they are considered to be client applications, and they will receive a client id and client secret upon registration.

By default, the Passport library already creates a couple of example clients when you run the PHP artisan passport:install command. Apart from that, it also allows you to create new clients as needed. The Passport library provides an artisan command to create client accounts without much hassle. Let's go ahead and create a demo client account.

1
$php artisan passport:client
2
3
 Which user ID should the client be assigned to?:
4
 > 3
5
6
 What should we name the client?:
7
 > Demo OAuth2 Client Account
8
9
 Where should we redirect the request after authorization? [https://localhost/auth/callback]:
10
 > http://localhost/oauth2_client/callback.php
11
12
New client created successfully.
13
Client ID: 3
14
Client secret: 1BT1tNj0Are27IGvIZe4lE2jRjtiVt0fmtaWBe8m

When you run the artisan passport:client command, it asks you a few questions before creating the client account. Out of those, there's an important one that asks you the callback URL.

The callback URL is the one where users will be redirected back to the third-party end after authorization. And that's where the authorization code that's supposed to be used in exchange for the access token will be sent. We're going to create that file in a moment.

Now, we're ready to test OAuth2 APIs in the Laravel application.

For demonstration purposes, I'll create the oauth2_client directory under the document root in the first place. Ideally, these files will be located at the third-party end that wants to consume APIs in our Laravel application.

Let's create the oauth2_client/auth_redirection.php file with the following contents.

1
<?php
2
$query = http_build_query(array(
3
    'client_id' => '3',
4
    'redirect_uri' => 'http://localhost/oauth2_client/callback.php',
5
    'response_type' => 'code',
6
    'scope' => '',
7
));
8
 
9
header('Location: http://your-laravel-site-url/oauth/authorize?'.$query);

Make sure to change the client_id and redirect_uri parameters to reflect your own settings—the ones that you used while creating the demo client account.

Next, let's create the oauth2_client/callback.php file with the following contents.

1
<?php
2
// check if the response includes authorization_code

3
if (isset($_REQUEST['code']) && $_REQUEST['code'])
4
{
5
    $ch = curl_init();
6
    $url = 'http://your-laravel-site-url/oauth/token';
7
 
8
    $params = array(
9
        'grant_type' => 'authorization_code',
10
        'client_id' => '3',
11
        'client_secret' => '1BT1tNj0Are27IGvIZe4lE2jRjtiVt0fmtaWBe8m',
12
        'redirect_uri' => 'http://localhost/oauth2_client/callback.php',
13
        'code' => $_REQUEST['code']
14
    );
15
 
16
    curl_setopt($ch,CURLOPT_URL, $url);
17
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
18
 
19
    $params_string = '';
20
 
21
    if (is_array($params) && count($params))
22
    {
23
        foreach($params as $key=>$value) {
24
            $params_string .= $key.'='.$value.'&';
25
        }
26
 
27
        rtrim($params_string, '&');
28
 
29
        curl_setopt($ch,CURLOPT_POST, count($params));
30
        curl_setopt($ch,CURLOPT_POSTFIELDS, $params_string);
31
    }
32
 
33
    $result = curl_exec($ch);
34
    curl_close($ch);
35
    $response = json_decode($result);
36
     
37
    // check if the response includes access_token

38
    if (isset($response->access_token) && $response->access_token)
39
    {
40
        // you would like to store the access_token in the session though...

41
        $access_token = $response->access_token;
42
 
43
        // use above token to make further api calls in this session or until the access token expires

44
        $ch = curl_init();
45
        $url = 'http://your-laravel-site-url/api/user/get';
46
        $header = array(
47
        'Authorization: Bearer '. $access_token
48
        );
49
        $query = http_build_query(array('uid' => '1'));
50
 
51
        curl_setopt($ch,CURLOPT_URL, $url . '?' . $query);
52
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
53
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
54
        $result = curl_exec($ch);
55
        curl_close($ch);
56
        $response = json_decode($result);
57
        var_dump($result);
58
    }
59
    else
60
    {
61
        // for some reason, the access_token was not available

62
        // debugging goes here

63
    }
64
}

Again, make sure to adjust the URLs and client credentials according to your setup in the above file.

How It Works Altogether

In this section, we'll test it altogether from the perspective of an end user. As an end user, there are two applications in front of you:

  1. The first one is the Laravel application which you already have an account with. It holds your information that you could share with other third-party applications.
  2. The second one is the demo third-party client application, auth_redirection.php and callback.php, which wants to fetch your information from the Laravel application using the OAuth API.

The flow starts from the third-party client application. Go ahead and open the http://localhost/oauth2_client/auth_redirection.php URL in your browser, and it should redirect you to the Laravel application. If you're not already logged in to the Laravel application, the application will ask you to do so.

Once the user is logged in, the application displays the authorization page.

If the user authorizes that request, the user will be redirected back to the third-party client application at http://localhost/oauth2_client/callback.php along with the code as the GET parameter that contains the authorization code.

Once the third-party application receives the authorization code, it could exchange that code with the Laravel application to get the access token. And that's exactly what it has done in the following snippet of the oauth2_client/callback.php file.

1
$ch = curl_init();
2
$url = 'http://your-laravel-site-url/oauth/token';
3
 
4
$params = array(
5
    'grant_type' => 'authorization_code',
6
    'client_id' => '3',
7
    'client_secret' => '1BT1tNj0Are27IGvIZe4lE2jRjtiVt0fmtaWBe8m',
8
    'redirect_uri' => 'http://localhost/oauth2_client/callback.php',
9
    'code' => $_REQUEST['code']
10
);
11
 
12
curl_setopt($ch,CURLOPT_URL, $url);
13
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
14
 
15
$params_string = '';
16
 
17
if (is_array($params) && count($params))
18
{
19
    foreach($params as $key=>$value) {
20
        $params_string .= $key.'='.$value.'&';
21
    }
22
 
23
    rtrim($params_string, '&');
24
 
25
    curl_setopt($ch,CURLOPT_POST, count($params));
26
    curl_setopt($ch,CURLOPT_POSTFIELDS, $params_string);
27
}
28
 
29
$result = curl_exec($ch);
30
curl_close($ch);
31
$response = json_decode($result);

Next, the third-party application checks the response of the CURL request to see if it contains a valid access token in the first place.

As soon as the third-party application gets the access token, it could use that token to make further API calls to request resources as needed from the Laravel application. Of course, the access token needs to be passed in every request that's requesting resources from the Laravel application.

We've tried to mimic the use-case in that the third-party application wants to access user information from the Laravel application. And we've already built an API endpoint, http://your-laravel-site-url/api/user/get, in the Laravel application that facilitates it.

1
// check if the response includes access_token

2
if (isset($response->access_token) && $response->access_token)
3
{
4
    // you would like to store the access_token in the session though...

5
    $access_token = $response->access_token;
6
 
7
    // use above token to make further api calls in this session or until the access token expires

8
    $ch = curl_init();
9
    $url = 'http://your-laravel-site-url/api/user/get';
10
    $header = array(
11
    'Authorization: Bearer '. $access_token
12
    );
13
    $query = http_build_query(array('uid' => '1'));
14
 
15
    curl_setopt($ch,CURLOPT_URL, $url . '?' . $query);
16
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
17
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
18
    $result = curl_exec($ch);
19
    curl_close($ch);
20
    $response = json_decode($result);
21
    var_dump($result);
22
}

So that's the complete flow of how you're supposed to consume OAuth2 APIs in Laravel.

And with that, we’ve reached the end of this article.

Conclusion

Today, we explored the Laravel Passport library in Laravel, which allows us to set up an OAuth2 server in an application very easily. 

For those of you who are either just getting started with Laravel or looking to expand your knowledge, site, or application with extensions, we have a variety of things you can study in Envato Market.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.