Skip to content

Instantly share code, notes, and snippets.

@murdercode
Last active December 4, 2023 08:29
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save murdercode/fdc7f36b6d20642fbffc825468509e29 to your computer and use it in GitHub Desktop.
Save murdercode/fdc7f36b6d20642fbffc825468509e29 to your computer and use it in GitHub Desktop.
Laravel Nova 4 + Auth0

Nova 4 + Auth0 = ❤️

Hi folks! After a day of *#!$", DispatchCode and I have realized a working installation of Nova4 with Auth0 support. Here's our conclusions, if you want to try it :)

2. Create the Custom Auth

Create a file in \app\Auth\CustomUserRepository.php and add the following code:

<?php
namespace App\Auth;
//...
class CustomUserRepository implements \Auth0\Laravel\Contract\Auth\User\Repository
{
    public function fromSession(array $user): ?\Illuminate\Contracts\Auth\Authenticatable
    {
         $user = cache()->remember('user_logged_' . $user['email'], 60, function () use ($user) {
            return \App\Models\User::firstOrCreate([
                'email' => $user['email'],
            ], [
                'name' => $user['name'],
                //'password' => bcrypt('secret'), // if you want a fallback
                'is_admin' => false,
            ]);
        });
        return $user;
    }

    public function fromAccessToken(
        array $user
    ): ?\Illuminate\Contracts\Auth\Authenticatable {
        // Simliar to above. Used for stateless application types.
        return null;
    }
}

3. Remove Nova routes login

This is useful if you don't want to see the standard login page after login (maybe there's a better option?).

In routes/web.php:

Route::get('/cms/login', function () {
    return redirect('/');
});

(optional, see 4) Also add an endpoint if you want to protect whole website:

Route::get('/', [HomeController::class, 'index'])->name('home');

4. HomeController

Skip if you don't want to protect whole website

Create HomeController

$ php artisan make:controller HomeController

then add:

<?php

namespace App\Http\Controllers;

class HomeController extends Controller
{
    public function index(): \Illuminate\Http\RedirectResponse
    {
        if (auth()->check()) {
            return redirect('/cms');
        }
        return redirect(route('login'));
    }
}

5. Adapt Model/User

In app\Models\User.php add the following:

<?php

use Auth0\Laravel\Contract\Model\Stateful\User as StatefulUser;

class User extends Authenticatable implements StatefulUser

...

public function canImpersonate()
{
    //return Gate::forUser($this)->check('viewNova');
    return false; // <- Impersonate (cannot?) works with Auth0
}

6. Assign Auth Custom Repository

In config/auth.php assign the repository at auth0 provider:

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],
    'auth0' => [
       'driver' => 'auth0',
       'repository' => App\Auth\CustomUserRepository::class // <- Here!
       'model' => App\Models\User::class, // <- Also here!
   ],
],

7. Seed error?

We got an error with the Util::class. Maybe is an isolated case, but if you got an error there's a temp workaround was to change the standard migration (you will need to publish the nova migrations):

In: database/migrations/2018_01_01_000000_create_action_events_table.php

Schema::create('action_events', function (Blueprint $table) {
$table->id();
$table->char('batch_id', 36);
$table->foreignIdFor(\App\Models\User::class)->index(); // <- Change this!
$table->string('name');
$table->morphs('actionable');
$table->morphs('target');
$table->string('model_type');
@s7thamon
Copy link

s7thamon commented Dec 12, 2022

This is great! I was pulling my hair out trying to get this working ❤️

Have you gotten this to work with the event actions table? use Laravel\Nova\Actions\Actionable;

It only seems to work if the default guard in auth.php is set for web, but this causes a login redirect loop. Changing it to auth0 allows the login to work but will throw an error for the Actions table:

image

[2022-12-12 22:13:07] local.ERROR: Class name must be a valid object or a string {"userId":1,"exception":"[object] (Error(code: 0): Class name must be a valid object or a string at /Users/Sites/matrix/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php:775)

    protected function newRelatedInstance($class)
    {
        return tap(new $class, function ($instance) {
            if (! $instance->getConnectionName()) {
                $instance->setConnection($this->connection);
            }
        });
    }

@s7thamon
Copy link

Not sure of any issues yet but I changed the following to the provider in auth.php and it seemed to resolve it:

        'auth0' => [
            'driver' => 'auth0',
            'repository' => App\Auth\CustomUserRepository::class,
            'model' => App\Models\User::class,
        ],

@murdercode
Copy link
Author

Not sure of any issues yet but I changed the following to the provider in auth.php and it seemed to resolve it:

        'auth0' => [
            'driver' => 'auth0',
            'repository' => App\Auth\CustomUserRepository::class,
            'model' => App\Models\User::class,
        ],

Hello,
that's probably the right way! We will try integrating it into one of our projects to see if it causes problems with testing but at first glance it looks like a good solution. I'll update the gist! ;)

@s7thamon
Copy link

Some more updates with newer version of the auth0 package. Drivers should be auth0.guard now and provider auth0.provider.

        'auth0' => [
            'driver' => 'auth0.guard',
            'provider' => 'auth0',
        ],
        'auth0' => [
            'driver' => 'auth0.provider',
            'repository' => App\Auth\CustomUserRepository::class,
            'model' => App\Models\User::class,
        ],

@murdercode
Copy link
Author

Some more updates with newer version of the auth0 package. Drivers should be auth0.guard now and provider auth0.provider.

        'auth0' => [
            'driver' => 'auth0.guard',
            'provider' => 'auth0',
        ],
        'auth0' => [
            'driver' => 'auth0.provider',
            'repository' => App\Auth\CustomUserRepository::class,
            'model' => App\Models\User::class,
        ],

Thanks mate, I'll try it soon :)

@s7thamon
Copy link

Well, one step closer another step back. Getting this error now, trying to figure it out:
Cannot assign App\Models\User to property Auth0\Laravel\Auth\User\Provider::$repository of type ?Auth0\Laravel\Contract\Auth\User\Repository. This is with Nova 4.24.2 and auth0 7.7.0

@s7thamon
Copy link

Have you gotten this to work with the latest changes to the auth0 package?

@murdercode
Copy link
Author

Have you gotten this to work with the latest changes to the auth0 package?

Not yet but we will work on it in next days ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment