Table of Content

When you have to choose how to start a new project you have many choices if you think about languages, frameworks and authentication.

In our case (we = company where I work) we’re going with a classic SPA: Vue + Laravel API. Additionally, we’re using Auth0 to authenticate our SPA, because it’s a company backoffice and with Auth0 we’re creating a kind-of-SSO between all our backoffices.
Sounds cool, right? I mean, there are plenty of tutorials about this for Vue. Indeed. But I found a lack of tutorial for Laravel.

Wait wait, does Auth0 have an official quickstart for Laravel? They have two!? One for classic webapp application and one as “API only”? This is awesome! And there’s more? Their guide is for Laravel 6? Well, I’m using Laravel 8, I’m sure it wor–. Yes, that’s why we’re here.

Installation

One of the best thing Auth0 did was a provider for Laravel to integrate their service: https://github.com/auth0/laravel-auth0. Before you go, I have to sadly inform you that when I’m writing this and the provider is at v6.1.0 it still doesn’t support Guzzle7, so you have to downgrade it to 6.5.5 by running composer require guzzlehttp/guzzle:^6.5.5. Very sad times. There’s already an issue for this, we hope they upgrade it soon.

Let’s focus folks and proceed with the tutorial: install the provider running composer require auth0/login:"~6.0" and the magic word of Laravel and Composer will automatically discover and register it.

Usage

Now, following their README, we can setup a Guard and using it as a middleware to protect our routes. Open your config/auth.php file and add a new Guard:

'guards' => [
    ...
    'auth0' => [
        'driver' => 'auth0',
        'provider' => 'auth0',
    ],
],

Now, in the same file, add the provider too:

'providers' => [
    ...
    'auth0' => [
        'driver' => 'auth0',
    ],
],

Given that, we can protect our routes using the guard as a middleware:

Route::get('/private', function () {
	return response()->json(['message' => 'Private endpoint']);
})->middleware('auth:auth0');

From now on, you can only access /private endpoint providing a valid JWT token in the Authorization header like this: Authorization: Bearer <jwt-here>.

Testing

Since Laravel 8 the way Models Factory are made is a bit different, in fact you have to add HasFactory trait to your model in order to create a new “fake” model. I think that currently Auth0 still does not support this for the Auth0User model and, because of that, we can’t (still) rely on Auth0User::factory() syntax.

To workaround this we’re just gonna initialize a new Auth0\Login\Auth0User instance and using that for the actingAs helper.

When creating an Auth0User instance you should provide 2 arguments:

  • array $userInfo , where you can find the sub key (provided by Auth0) or the user_id key;
  • string|null $token - I think this is the JWT, but I don’t really know.

Anyway for our test where we don’t need to store the user nor to retrieve it from the sub / user_id property, we can just leave them both “empty”.

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Auth0\Login\Auth0User;
use Illuminate\Http\Response;

class PrivateEndpointTest extends TestCase
{
  /**
   * @testdox returns ok if providing a valid token.
   *
   * @return void
   */
  public function testAuthorizedWithFakeUser()
  {
    $user = new Auth0User([], null);

    $this->actingAs($user, 'auth0')
      ->getJson('/api/private')
      ->assertStatus(Response::HTTP_OK)
      ->assertExactJson([
        'message' => 'Private endpoint',
      ]);
  }
}