Skip to content

Instantly share code, notes, and snippets.

@murdercode
Last active August 6, 2024 20:11
Show Gist options
  • 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 ;)

@lCHECHOl
Copy link

lCHECHOl commented Jul 27, 2024

Hi, I'm getting this error when I extend Auth0\Laravel\Users\StatefulUserContract as StatefulUser in my user model, I'm trying to solve it by overwriting the method __get of eloquent model class in my User.php model same as the method __get of the Auth0\Laravel\Users\UserContract interface, but does'nt work, any solution for that?, thanks in advance for everyone.

@lCHECHOl
Copy link

lCHECHOl commented Aug 6, 2024

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

@murdercode @s7thamon I am having the same problem; were you able to solve it somehow?

On the other hand, I posted this issue I'm having when trying to sync the logout from Nova with the Auth0 controller to log out. Do you know how you could help me?

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