HasPasskeys Trait
The HasPasskeys trait is provided by the package to wire up the polymorphic Eloquent relationship between any model (typically User) and the Passkey model.
Setup
Add the trait to your User model:
use Xefi\LaravelPasskey\Traits\HasPasskeys;
class User extends Authenticatable
{
use HasPasskeys;
}
Relationship
The trait exposes a single passkeys() relationship method:
public function passkeys(): MorphMany
{
return $this->morphMany(Passkey::class, 'passkeeable');
}
This is a polymorphic relationship — the passkeys table stores the owner's class and ID via passkeeable_type and passkeeable_id. This means you can attach passkey to any model, not just User.
// Get all passkey for a user
$passkeys = $user->passkeys;
// Count passkey
$count = $user->passkeys()->count();
// Check if user has any passkey
$hasPasskeys = $user->passkeys()->exists();
// Delete all passkey for a user
$user->passkeys()->delete();
Customization methods
The trait provides two methods you can override in your model to control how user data is exposed during passkey operations.
getPasskeyDisplayName()
Returns the display name used during passkey registration and included in /login responses.
public function getPasskeyDisplayName(): string
{
return $this->name ?? $this->email ?? (string) $this->getKey();
}
Override it in your model if the display name comes from a different field:
public function getPasskeyDisplayName(): string
{
return $this->display_name ?? $this->username;
}
getPasskeyEmail()
Returns the email used during passkey registration and included in /login responses.
public function getPasskeyEmail(): string
{
return $this->email ?? '';
}
Override it if your model stores the email under a different attribute:
public function getPasskeyEmail(): string
{
return $this->email_address;
}
Cascade deletion
The trait registers a deleting model event via bootHasPasskeys(). When the owning model is deleted, all its associated passkey are automatically deleted:
protected static function bootHasPasskeys(): void
{
static::deleting(function ($model) {
$model->passkeys()->delete();
});
}
CASCADE constraint. Make sure you delete models through Eloquent (not raw SQL) for this to trigger.