---
title: "DI and actions — Passkeys for Laravel | Roundly"
description: "Inject PasskeyService for the same API without static calls, or run a ceremony’s single-purpose action directly from trusted code."
url: https://roundly-consulting.com/open-source/docs/passkeys-for-laravel/without-facade
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Passkeys for Laravel](https://roundly-consulting.com/open-source/docs/passkeys-for-laravel.md)

# DI and actions

There are three equivalent entry points, and the choice is yours:

- The Passkeys facade — the shortest, and the recommended default.
- The service, injected through the constructor — the same API as an explicit dependency, with no static calls. Type-hint the RoundlyConsulting\\Passkeys\\Contracts\\PasskeyService contract: it is the facade root, bound to RoundlyConsulting\\Passkeys\\PasskeyManager. The manager is bound only under the contract, not as its own singleton — inject the contract, not the class.
- Actions — single-purpose classes with an execute() method, for composing into your own actions, jobs and commands.

## Injecting the service

Passkeys::fake() swaps the PasskeyService binding, so constructor-injected code sees the fake too:

```php
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use RoundlyConsulting\Passkeys\Contracts\PasskeyService;

final readonly class RevokePasskeyController
{
    public function __construct(private PasskeyService $passkeys) {}

    public function __invoke(Request $request, int $passkey): Response
    {
        $this->passkeys->for($request->user())->revoke($passkey);

        return response()->noContent();
    }
}
```

## Running an action

Each facade call is one action, resolved from the container:

| Facade call | Action |
| --- | --- |
| `for($user)->registrationOptions($o)` | `GenerateRegistrationOptionsAction::execute($user, $o)` |
| `for($user)->register($r, $name)` | `VerifyRegistrationAction::execute($user, $r, $name)` |
| `for($user)->authenticationOptions($o) / authenticationOptions($o)` | `GenerateAuthenticationOptionsAction::execute(?$user, $o)` |
| `for($user)->authenticate($r) / authenticate($r, $expect)` | `VerifyAuthenticationAction::execute($r, ?$expect)` |
| `for($user)->rename($p, $name)` | `RenamePasskeyAction::execute($passkey, $name)` |
| `for($user)->revoke($p)` | `RevokePasskeyAction::execute($passkey)` |

```php
use RoundlyConsulting\Passkeys\Actions\GenerateRegistrationOptionsAction;
use RoundlyConsulting\Passkeys\Actions\RevokePasskeyAction;
use RoundlyConsulting\Passkeys\Actions\VerifyRegistrationAction;
use RoundlyConsulting\Passkeys\Models\Passkey;

// The same two registration calls, one action each:
$options = app(GenerateRegistrationOptionsAction::class)->execute($user, $overrides);
$passkey = app(VerifyRegistrationAction::class)->execute($user, $response, 'MacBook Touch ID');

// Trusted code that already scoped its query — the action itself checks no ownership:
Passkey::query()
    ->ownedBy($user)
    ->where('last_used_at', '<', now()->subYear())
    ->each(fn (Passkey $passkey) => app(RevokePasskeyAction::class)->execute($passkey));
```

RenamePasskeyAction and RevokePasskeyAction take a resolved Passkey and check no ownership — the account handle does that. Call them directly only from trusted code, such as an admin tool or a job that already scoped its query.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/passkeys-for-laravel.md)
