2

My setup

  • Laravel 8
  • Laravel Spark Mollie

I'm constantly hitting a brick wall when calling API requests with Spark & Sanctum. I've installed Sanctum with no problem and migrated.

I've added use Laravel\Sanctum\HasApiTokens; to app/Models/User.php and added use HasApiTokens; to the class.

My Api.php route

Route::group([
    'middleware' => 'auth:sanctum'
], function () {
    Route::get('categories', [\App\Http\Controllers\categories::class, 'fetchCategories']);
});

When I call the Api I get this error

ErrorException
Declaration of Laravel\Sanctum\HasApiTokens::tokenCan(string $ability) should be compatible with Laravel\Spark\User::tokenCan($ability)

I've tried changing use Laravel\Sanctum\HasApiTokens; to Laravel\Spark\HasApiTokens on User.php. The error goes away, but whenever I try calling the Api, it returns me back to the login homepage.

Any ideas? As the Spark documentation doesn't really explain how Sanctum or Api protection work.

Vinnie
  • 81
  • 4

1 Answers1

0

The problem is that your main User class extends the User class from the vendor Spark library. This User model uses the trait named HasApiTokens which is not the same as Sanctum

Since you don't want to change the file from the vendor directory, one fix I found was to copy the original SparkUser model class from the vendor and create a new one like this and remove the trait HasApiTokens since you don't want to use it anymore.

<?php

namespace App\Models\Users;

use Illuminate\Support\Str;
use Laravel\Spark\Billable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class SparkUser extends Authenticatable
{
    use Billable, Notifiable; // HasApiTokens was removed from the original SparkUser class

/**
 * Get the profile photo URL attribute.
 *
 * @param  string|null  $value
 * @return string|null
 */
public function getPhotoUrlAttribute($value)
{
    return empty($value) ? 'https://www.gravatar.com/avatar/'.md5(Str::lower($this->email)).'.jpg?s=200&d=mm' : url($value);
}

/**
 * Make the team user visible for the current user.
 *
 * @return $this
 */
public function shouldHaveSelfVisibility()
{
    return $this->makeVisible([
        'uses_two_factor_auth',
        'country_code',
        'phone',
        'card_brand',
        'card_last_four',
        'card_country',
        'billing_address',
        'billing_address_line_2',
        'billing_city',
        'billing_state',
        'billing_zip',
        'billing_country',
        'extra_billing_information'
    ]);
}

/**
 * Convert the model instance to an array.
 *
 * @return array
 */
public function toArray()
{
    $array = parent::toArray();

    if (! in_array('tax_rate', $this->hidden)) {
        $array['tax_rate'] = $this->taxPercentage();
    }

    return $array;
}

}

And now all I had to change was my original User class model to use this new model like this and add the trait HasApiTokens from Sanctum!

use App\Models\SparkUser; // Modified from the original in the vendor folder
use Laravel\Sanctum\HasApiTokens;

class User extends SparkUser
{
    use HasApiTokens;
    
    ...
}
Sam Bellerose
  • 1,782
  • 2
  • 18
  • 43