GodziLaravel's avatar

Laravel sanctum, after switching to UUID: General error: 1364 Field 'id' doesn't have a default value

hello ,

I try to configure Laravel sanctum ,

This is the migration content for personal_access_tokens:

public function up(): void
    {
        Schema::create('personal_access_tokens', function (Blueprint $table) {
            $table->uuid('id')->primary();
            $table->uuidMorphs('tokenable');
            $table->string('name');
            $table->string('token', 64)->unique();
            $table->text('abilities')->nullable();
            $table->timestamp('last_used_at')->nullable();
            $table->timestamp('expires_at')->nullable();
            $table->timestamps();
        });
    }

Route :

Route::controller(RegisterController::class)->group(function(){
    Route::post('register', 'register');
    Route::post('login', 'login');
});

RegisterController

 public function register(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'first_name' => 'required',
            'last_name' => 'required',
            'email' => 'required|email',
            'password' => 'required',
            'c_password' => 'required|same:password',
        ]);

        if($validator->fails()){
            return $this->sendError('Validation Error.', $validator->errors());
        }

        $input = $request->all();
        $input['password'] = bcrypt($input['password']);
        $user = User::create($input);
        $success['token'] =  $user->createToken('MyApp')->plainTextToken;
        $success['name'] =  $user->name;

        return $this->sendResponse($success, 'User register successfully.');
    }

when I run the register API :

Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1364 Field 'id' doesn't have a default value (Connection: mysql, SQL: insert into `personal_access_tokens` (`name`, `token`, `abilities`, `expires_at`, `tokenable_id`, `tokenable_type`, `updated_at`, `created_at`) values (MyApp, f0665ae9d2e56de428066559ddb40be8f8fe6ce576e2efb68507ee2a6a1e2c44, ["*"], ?, 4372b64d-e398-4e54-8f26-db1d424c1685, App\Models\User, 2023-04-09 22:04:09, 2023-04-09 22:04:09)) in file /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 793

It seems like it's not taking in account that "id" is UUID !

Remark :

The User model works fine without any problem!

I added uuid traits and I use it from all models :

namespace App\Traits;

use Illuminate\Support\Str;
trait Uuids
{
    /**
     * Boot function from Laravel.
     */
    protected static function boot()
    {
        parent::boot();
        static::creating(function ($model) {
            if (empty($model->{$model->getKeyName()})) {
                $model->{$model->getKeyName()} = Str::uuid()->toString();
            }
        });
    }

    /**
     * Get the value indicating whether the IDs are incrementing.
     *
     * @return bool
     */
    public function getIncrementing()
    {
        return false;
    }

    /**
     * Get the auto-incrementing key type.
     *
     * @return string
     */
    public function getKeyType()
    {
        return 'string';
    }
}
Any idea please  ?
0 likes
4 replies
VolhaR's avatar

I had the same problem. My solution is adding HasUuids to Migration and use method newUniqueId(), like this 'id' => $this->newUniqueId(),

Daniesy's avatar

For anyone who might have this problem, I ended up doing the following.

Add a new method in the User model called createUuidToken:

public function createUuidToken(string $name, array $abilities = ['*'], ?DateTimeInterface $expiresAt = null)
    {
        $plainTextToken = $this->generateTokenString();

        $token = $this->tokens()->forceCreate([
            'id' => $this->newUniqueId(),
            'name' => $name,
            'token' => hash('sha256', $plainTextToken),
            'abilities' => $abilities,
            'expires_at' => $expiresAt,
        ]);

        return new NewAccessToken($token, $token->getKey().'|'.$plainTextToken);
    }

Call this method in the controller instead of the original createToken one:

    public function generateToken(TokenRequest $request): RedirectResponse
    {
        $stringToken = $request->user()->createUuidToken($request->token_name)->plainTextToken;

        // ...
    }
vagkaefer's avatar

You can change the default Token model

UsesUuid Trait:

The new model:

<?php

namespace App\Models;

use Laravel\Sanctum\PersonalAccessToken as SanctumPersonalAccessToken;
use App\Traits\UsesUuid;

class PersonalAccessToken extends SanctumPersonalAccessToken
{
    use UsesUuid;
}

Then change your AppServiceProvider:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Laravel\Sanctum\Sanctum;
use App\Models\PersonalAccessToken;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
     
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
    }
}

This way you can reuse the UsesUuid with others Models

More info in the docs: https://laravel.com/docs/11.x/sanctum#overriding-default-models

Please or to participate in this conversation.